Windows DevCenter    
 Published on Windows DevCenter (http://www.windowsdevcenter.com/)
 See this if you're having trouble printing code examples


Unit Testing in Visual Studio 2005 Team System

by Wei-Meng Lee
01/03/2006
Use ClickOnce to Deploy Windows Applications

Unit testing is one of the tasks that every programmer worth their salt needs to do. For example, after writing a class, you often need to write additional code to instantiate the class and test the various methods and properties defined within it. With Visual Studio 2005 Team System, you can now use the new Unit Testing feature to auto-generate the code needed to test your application.

In this article, I will show you how unit testing is performed in Visual Studio 2005 Team System. Note that you need the Microsoft Visual Studio 2005 Beta 2 Team Edition to try the example in this article.

Creating the Application

Launch Visual Studio 2005 and create a new Windows project using the Visual Basic 2005 language. Name the project UnitTesting.

Let's start by first adding a class to the project. Right-click on the project name in Solution Explorer and select Add->New Item…. Select the Class template and name it as Point.vb.

Populate the Point.vb file with the following class definition:

Public Class Point
    Private pX, pY As Integer

    '---default constructor
    Public Sub New()

    End Sub

    '---constructor with two parameters
    Public Sub New(ByVal x As Integer, ByVal y As Integer)
        pX = x
        pY = y
    End Sub

    '---sets the X coordinate
    Property x() As Integer 
        Get
            Return pX
        End Get
        Set(ByVal Value As Integer)
            pX = Value
        End Set
    End Property

    '---sets the Y coordinate
    Property y() As Integer 
        Get
            Return pY
        End Get
        Set(ByVal Value As Integer)
            pY = Value
        End Set
    End Property

    '---calculates the length between 2 points
    Public Function length(ByVal pointOne As Point) As Single
        Return Math.Sqrt(Math.Pow(pX - pointOne.x, 2) + _
               Math.Pow(pY - pointOne.y, 2))
    End Function
End Class

This class represents points on a two-dimension system, with x and y coordinates and a method to calculate the distance between two points.

Visual Studio Hacks

Related Reading

Visual Studio Hacks
Tips & Tools for Turbocharging the IDE
By James Avery

Creating a Test

We will now create a test for the length() method to ensure that the result returned by it is what we expected.

To create a test for the length() method, right-click on the method name and select Create Tests… (see Figure 1).

Figure 1
Figure 1. Creating a test for a method

A window will be displayed to allow you to create additional tests for other methods and properties (see Figure 2). The Output project drop-down list box lets you choose to create a test project using either Visual Basic, C#, or C++. Choose Visual Basic and click OK.

Figure 2
Figure 2. Generate unit tests

You will be prompted to give a name to the test project. Use the default TestProject1 and click Create. The TestProject1 will now be added to Solution Explorer (see Figure 3).

Figure 3
Figure 3. The test project in Solution Explorer

The PointTest.vb class will now be displayed in Visual Studio 2005 (see Figure 4). This class will contain the various test methods that you can use to test the Point class.

Thumbnail, click for full-size image.
Figure 4. The PointTest.vb file--click for full-size image.

Within the PointTest.vb file, the lengthTest() method is the method that performs the actual test on the length() method in our Point class:

<TestMethod()> _
Public Sub lengthTest()
    Dim x As Integer 'TODO: Initialize to an appropriate value

    Dim y As Integer 'TODO: Initialize to an appropriate value

    Dim target As Point = New Point(x, y)

    Dim pointOne As Point = Nothing 'TODO: Initialize to an appropriate 
                                    ' value

    Dim expected As Single
    Dim actual As Single

    actual = target.length(pointOne)

    Assert.AreEqual(expected, actual, _
       "UnitTesting.Point.length did not return the expected value.")
    Assert.Inconclusive("Verify the correctness of this test method.")

End Sub

Note that the method has the <TestMethod> attribute prefixing it. Methods with this attribute are known as test methods.

Let's modify the implementation of the lengthTest() method. Basically we will create and initialize two Point objects and then call the length() method of the Point class to calculate the distance between the two points:

<TestMethod()> _
Public Sub lengthTest()
    Dim x As Integer = 3
    Dim y As Integer = 4

    Dim target As Point = New Point(x, y)

    Dim pointOne As Point = New Point(0, 0)

    Dim expected As Single = 5
    Dim actual As Single

    actual = target.length(pointOne)
    Assert.AreEqual(expected, actual, _
       "UnitTesting.Point.length did not return the expected value.")
End Sub

Once the result is returned from the length() method, we will use the AreEqual() method from the Assert class to check the returned value with the expected value. If the expected value does not match the returned result, the error message set in the AreEqual() method will be displayed.

Running the Test

To run the test, first set the TestProject1 as the startup project (right-click on TestProject1 in Solution Explorer and select Set as Startup Project).

Press F5 and observe the results shown in the Test Results window (see Figure 5).

Figure 5
Figure 5. Running the test

In this case, the lengthTest() method passed the test. The length between two points (3,4) and (0,0) is indeed 5.

You can make modifications to the lengthTest() method to test other additional parameters. In the Test Results window, you have the option to view the previous test results (see Figure 6).

Figure 6
Figure 6. Viewing the previous test results

You need to take special note when your test involves comparing floating point numbers. Consider the following example:

<TestMethod()> _
Public Sub lengthTest()
    Dim x As Integer = 4
    Dim y As Integer = 5

    Dim target As Point = New Point(x, y)

    Dim pointOne As Point = New Point(1, 2)

    Dim expected As Single = 4.24264
    Dim actual As Single

    actual = target.length(pointOne)
    Assert.AreEqual(expected, actual, _ 
       "UnitTesting.Point.length did not return the expected value.")
End Sub

If you were to manually calculate the length between the two points (4,5) and (1,2), you would indeed obtain the correct result as expected: 4.24264. However, when you run the test, you would notice that the test failed (see Figure 7).

Figure 7
Figure 7. The lengthTest method failed

Why is this so? The reason is that floating point numbers (such as Single and Double) are not stored exactly as what they have been assigned. For example, in this case, the value of 4.24264 is stored internally as 4.24264001846313, and the result returned by the length() method is actually 4.24264049530029. Hence the AreEqual() method will actually fail if you compare them directly.

To address this issue, the AreEqual() method supports a third parameter: delta. The delta parameter specifies the maximum difference allowed for the two numbers that you are comparing. In this case, the difference between the two numbers in question is 0.00000047683716. And so the following code will pass the test:

<TestMethod()> _
Public Sub lengthTest()
    Dim x As Integer = 4
    Dim y As Integer = 5

    Dim target As Point = New Point(x, y)

    Dim pointOne As Point = New Point(1, 2)

    Dim expected As Single = 4.24264
    Dim actual As Single

    actual = target.length(pointOne)

    Assert.AreEqual(expected, actual, 0.00000047683716, _
       "UnitTesting.Point.length did not return the expected value.")
End Sub

But the following will fail the test (see Figure 8):

  Assert.AreEqual(expected, actual, 0.00000047683715, _
     "UnitTesting.Point.length did not return the expected value.")

Figure 8
Figure 8. The lengthTest() method failed the test

The following tests will also pass:

     Assert.AreEqual(expected, actual, 0.00000047683716, _
        "UnitTesting.Point.length did not return the expected value.")
     
     Assert.AreEqual(expected, actual, 0.00000047683717, _
        "UnitTesting.Point.length did not return the expected value.")

In general, when comparing floating point numbers, it would be useful to specify a small delta, such as 0.05, to compensate for the rounding errors inherent in storing floating point numbers.

Adding Additional Test Methods

You can insert additional test methods by adding new subroutines to the PointTest.vb file and prefixing them with the <TestMethod> attribute. For example, the following test method uses the AreSame() method of the Assert class to check whether two objects are the pointing to the same reference:

  <TestMethod()> _
  Public Sub objectTest()
  
      Dim point1 As Point = New Point(4, 5)
  
      Dim point2 As New Point
      point2.x = 4
      point2.y = 5
  
      Dim point3 As Point = point2
  
      Assert.AreSame(point1, point2)  '--Failed
      Assert.AreSame(point2, point3)  '--Passed
  End Sub

Figure 9 shows the result of the two test methods in the PointTest.vb file: lengthTest and objectTest.

Figure 9
Figure 9. Viewing the test results

Summary

In this article, I have shown you how you can perform unit testing on your application using the Visual Studio 2005 Team System. Let me know if this feature is useful to you via the talkback below.

Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.


Return to the Windows DevCenter.

Copyright © 2009 O'Reilly Media, Inc.