AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=2053&pId=-1
Unit Testing Using Visual Studio 2010
page
by Vince Varallo
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 18914/ 104

Introduction

One of the steps all good developers take when developing an application is unit testing.  Unit testing involves testing a single method or function to ensure it is behaving as expected.  From what I've seen through real life experience is that when a developer initially develops his or her method they thoroughly unit test it. However, when changes are made for a new release I've seen the process fall apart.  A lot of time developers make the change that was requested and only test the scenario that was requested without going back to make sure other scenarios didn't break.  I'm guilty of this myself.

Visual Studio has a great unit testing framework which can help solve this problem.  You can build  unit testing scripts, which are essentially classes that call your code that you can then execute to determine if you're code is working correctly.  When you make an enhancement or re-factor your code you can simply run the unit test scripts to determine that the code is still functioning properly. It will take you extra time to initially develop your code but it is worth the investment knowing that your code is working correctly and that you can more easily maintain your code with confidence.

This article will show you how to create an ASP.NET application and how to unit test the ASP.NET web page and a public class in a class project.  It will also demonstrate how to execute your unit tests individually or in a group. The code for this sample can be found here.

Step 1: Create the TripCalculator Solution

The application being built will allow a user to enter speed and time and will calculate the distance traveled.  The calculation will be built into a class which represents the business layer of an application. 

1.    Launch Visual Studio 2010.  From the start page select "New Project…"

2.    Select ASP.NET Empty Web Application from the list of templates and name the application "TripCalculator".

3.    Click on FileàAdd New Project from the main menu.

4.    The Add New Dialog will appear.  Click on "Visual C#" from the list of Installed Templates.  Choose "Class Library" from the list of templates.  Name the project "TripCalculatorBLL" and click the OK button.

5.    Visual Studio will add this project to your solution and create a class file called "Class1.cs".  Right click on the Class1.cs file in the Solution Explorer and select Rename from the pop-up menu.  Change the name to "DistanceCalculator.cs".  Visual Studio will ask if you want to rename all references to this new name, click the "Yes" button.

6.    Add the following method to the DistanceCalculator class.

public double CalculateDistance(double time, double speed)
{
    if (time < 0 || speed < 0)
    {
        throw new ArgumentOutOfRangeException();
    }
    else
    {
        return time * speed;
    }
}

7.    This method will calculate the distance given the time and speed.  If the time or speed parameters are less than zero then it throws an ArgumentOutOfRangeException.

8.    Now let's add a web form that can use this class.  Right click on the TripCalcualtor project and select AddàNew Item from the pop-up menu.

9.    Select the WebForm template and name the file Default.aspx.  Click the Add button.

10.  Add a reference to the TripCalculator project to the TripCalculatorBLL project.  To do this right click on the References in the TripCalculator project. 

11. Click Add Reference… from the pop-up menu.

12. Click on the Projects tab from the References dialog.

13. Select the TripCalculatorBLL project from the list and click the OK button.

14. Add the following HTML to the web form.

<asp:Label ID="Label1" runat="server" Text="Time:"></asp:Label>
<asp:TextBox ID="txtTime" runat="server"></asp:TextBox>
<br />
<asp:Label ID="Label2" runat="server" Text="Speed:"></asp:Label>
<asp:TextBox ID="txtSpeed" runat="server"></asp:TextBox>
<br />
<asp:Label ID="Label3" runat="server" Text="Distance:"></asp:Label>
<asp:Label ID="lblDistance" runat="server"></asp:Label>
<br />
<asp:Button ID="btnCalculate" runat="server" Text="Calculate" />

15. If you switch to Design mode your form should look like the following image.

16. Double click on the Calculate button to create the event handler.

17. Add the following using statement to the code behind page.

using TripCalculatorBLL;

18. Add the following code to the click event handler.

try
{
    DistanceCalculator distanceCalculator = new DistanceCalculator();
    lblDistance.Text = distanceCalculator.CalculateDistance
        (Convert.ToDouble(txtTime.Text), 
        Convert.ToDouble(txtSpeed.Text)).ToString();
}
catch (Exception ex)
{
    lblDistance.Text = ex.Message;
}

19. Try running the project and enter 5 for the Time and 5 for the Speed.  If you click the Calculate button you should get 25 for the Distance.

Step 2: Create the Unit Tests

Now that you have your code in place you can create your unit tests to validate your code.  Your unit tests will go into a separate project designed specifically to test your code.  You have the ability to add unit tests to your project but it is not recommended because you don't want to deploy your tests to production.  Putting them in a separate project allows you to test your project without affecting production.

1.    Right click on the TripCalculator solution in the Solution Explorer and select AddàNew Project… from the pop-up menu.

2.    Click "Test" from the list of installed Visual C# templates and choose the Test Project template.

3.    Name the project "TripCalculatorTest" and click the OK button.

1.    The TripCalculatorTest project will be added with a single class called UnitTest1.cs.  Delete this class from your project.

2.    Right click on the TripCalculatorTest project and select AddàNew Test from the pop-up menu.

3.    The Add New Test dialog should appear.

4.    Select the Unit Test Wizard template and click the OK button.

5.    The Create Unit Test Wizard will appear.  The screen shows you the list of projects in your solution that you can test.  We'll first add a unit test to test the CalculateDistance method in the TripCalculatorBLL.DistanceCalculator class.  You can expand each node on the screen by clicking the arrow next to the name of the namespace or class that you want to test.  Check the box next to the CalculateDistance method.

6.    Click the OK button.

7.    A new class called DistanceCalculatorTest.cs will be added to your project.  The code for this class is as follows:

using TripCalculatorBLL;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
 
namespace TripCalculatorTest
{   
    /// <summary>
    ///This is a test class for DistanceCalculatorTest and is intended
    ///to contain all DistanceCalculatorTest Unit Tests
    ///</summary>
    <span class=Bold>[TestClass()]</span>
    public class DistanceCalculatorTest
    {
        <span class=Bold>private TestContext testContextInstance;</span>
 
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }
 
        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running 
        //the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion
 
 
        /// <summary>
        ///A test for CalculateDistance
        ///</summary>
        <span class=Bold>[TestMethod()]</span>
        public void CalculateDistanceTest()
        {
            DistanceCalculator target = new DistanceCalculator(); 
            // TODO: Initialize to an appropriate value
            double time = 0F; // TODO: Initialize to an appropriate value
            double speed = 0F; // TODO: Initialize to an appropriate value
            double expected = 0F; // TODO: Initialize to an appropriate value
            double actual;
            actual = target.CalculateDistance(time, speed);
            Assert.AreEqual(expected, actual);
            Assert.Inconclusive("Verify the correctness of this test method.");
        }
    }
}

8.    One of the first things to notice is the use of the Microsoft.VisualStudio.TestTools.UnitTesting namespace.  This namespace contains the objects that you'll want to use to manipulate your tests.  One of the main objects used in this namespace is the "Assert" object.  This is used to validate your expected results against your actual results.  I'll demonstrate how this works soon.

9.    Notice that the class has an attribute called [TestClass()].  This tells Visual Studio that test methods reside in this class and they should be run when the unit tests are run.

10. There is a private object called TestContext which is also found in the Microsoft.VisualStudio.TestTools.UnitTesting namespace.  This object is used to setup certain parameters of the testing such as a connection to a database.

11. The next region is called "Additional Test Attributes".  This is commented out but can be used to run specific code when the class is initialized, destroyed, or every time a test in this class is executed or finished.  For now we'll just leave these commented out.

12. The code that will test our CalculateDistance method is tested by the CalculateDistanceTest method.

/// <summary>
///A test for CalculateDistance
///</summary>
<span class=Bold>[TestMethod()]</span>
public void CalculateDistanceTest()
{
   DistanceCalculator target = new DistanceCalculator(); 
   // TODO: Initialize to an appropriate value
   double time = 0F; // TODO: Initialize to an appropriate value
   double speed = 0F; // TODO: Initialize to an appropriate value
   double expected = 0F; // TODO: Initialize to an appropriate value
   double actual;
   actual = target.CalculateDistance(time, speed);
   Assert.AreEqual(expected, actual);
   Assert.Inconclusive("Verify the correctness of this test method.");
}

13. The wizard looked at the parameters of the CalculateDistance method and created local variable that you should initialize with your test data to test your method.  Set the time variable to 5 and the speed variable to 6.  Set the expected variable to 30.

14. Notice that the "actual" variable is being set to the return value of the CalculateDistance method.  The Assert.AreEqual method will validate that the expected value is the same as the actual value.  If they aren't the test will fail and it will appear in the TestResults view.

15. Comment out the Assert.Inconclusive line.  This isn't needed.

16. To run this test you simply need to right click anywhere in the CalculateDistanceTest method and select "RunTests" from the pop-up menu.

17. Visual Studio will compile the project and run the CalculateDistanceTest method.  The TestResult view will show you whether the test passed or not.

18. Now let's change the code to cause it to not pass so we can see the result view.  If you change the time to 7 and then run the test again it should fail.

19. Notice in the Test Result view the Result is Fail and it has a red X next to it.  You can double click on the row in the Test Result view and it will show you more detail about what was expected and what was the actual.

20. Now let's test that if you pass in a negative time that the method throws an exception.  Click back to the DistanceCalculatorTest class.  Add a new method to test throwing an exception by adding the following method.

[TestMethod()]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void CalculateDistanceTest2()
{
    DistanceCalculator target = new DistanceCalculator(); 
    double time = -1; 
    double speed = 6;
    double actual;
    actual = target.CalculateDistance(time, speed);            
}

21. Notice that this method has an attribute called "ExpectedException" which tell the unit testing framework to expect that this code will throw the ArgumentOutOfRangeException.  This is very helpful in order to fully test your code. 

22. If you right click in this method and run the test you should also get a result of Passed.

23. Now that you have two test methods you may want to run all the tests at once.  To do this click on TestàRunàAll Tests In Solution from the main menu.  This will run all the tests and show you the results in the Test Result view.

24. If you want to step through your test code you need to run the test in debug mode.  First, put a breakpoint in the test method you want to step through.  Select TestàDebugàTests in Current Context from the main menu.  Visual Studio will start the unit testing framework and will stop at your breakpoint.  You can then debug your test code just as you would normally debug any other code.

Step 3: Unit Test the Web Page

Now that we have successfully tested our CalculateDistance method we can test our web page to make sure the btnCalculate_Click event is functioning properly.

1.    Open the code behind page for the Default.aspx page.

2.    Right click in the btnCalculate_Click event and select "Create Unit Test…" from the pop-up menu.  The Create Unit Tests dialog will appear.

3.    Click the OK button.  Visual Studio will add a new test class to the TripCalculatorTest project called DefaultTest.cs.

4.    Add the following using statements to the top of the DefaultTest.cs file.

using System.Web.UI;
using System.Web.UI.WebControls;

5.    Scroll down in the DefaultTest class to the btnCalculate_ClickTest method.  Notice the attributes associated with this method.  They tell the unit testing framework which page to launch when running this test.

6.    Replace the code within the method with the following code.

public void btnCalculate_ClickTest()
{
    Page page = TestContext.RequestedPage;
 
    TextBox txtTime = (TextBox)page.FindControl("txtTime");
    txtTime.Text = "5";
 
    TextBox txtSpeed = (TextBox)page.FindControl("txtSpeed");
    txtSpeed.Text = "6";
 
    PrivateObject privateObject = new PrivateObject(page);
    Button btnCalculate = (Button)page.FindControl("btnCalculate");
    privateObject.Invoke("btnCalculate_Click", btnCalculate, EventArgs.Empty);
 
    Label lblDistance = (Label)page.FindControl("lblDistance");
 
    Assert.AreEqual("30", lblDistance.Text);
}

This code will first get a reference to the page that is being tested.  It then gets a reference to the two textboxes on the web page and sets their text properties.

The code then creates an instance of an object called a PrivateObject.  This object is in the Microsoft.VisualStudio.TestTools.UnitTesting namespace.  This object will allow you to access private methods or objects in your code.  You should never change the scope of an object just so you can test it.

The Invoke method of the PrivateObject is called to fire the btnCalculate_Click event.  The code then checks that the text of the lblDistance label matches the expected result.  If you right click in this test method and select Run Tests from the pop-up menu you will run this test.

Summary

Unit testing is essential when writing any application.  As a developer we are usually writing systems to automate some business process.  That is exactly what Microsoft has done for us in the case of the unit testing business process.  They have given us a great tool that will allow us as a developer to automate the task of unit testing our code.  This greatly reduces the risks of introducing bugs when enhancements or revisions are made to existing code.  The step of automating your unit tests should be an essential step in any development effort.  There are many more capabilities in the unit testing framework that I will try to address in more detail in future articles.

Good luck on your project and happy coding. 



©Copyright 1998-2014 ASPAlliance.com  |  Page Processed at 9/1/2014 3:27:38 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search