Working with Visual Studio Team Edition for Testers

oorly-written code and nonconformance to coding standards may get an application ready to ship a little more quickly, but often becomes a nightmare after application deployment. The answer is, of course, properly planned code testing that parallels your development cycle. Test Driven Development (TDD) simplifies development and reduces bugs and complexity by driving the development life cycle of your project using predefined tests. Initially, implementing TDD was difficult, but as it gains favor among development teams, it’s also gaining support from major tools vendors. In this article you’ll see how to use Visual Studio Team Edition for Testers (VSTET) to design and implement unit tests and web tests in your applications.

In the book “Practical TDD and Acceptance TDD for Java Developers,” Lasse Koskela writes, “TDD is a way of programming that encourages good design and is a disciplined process that helps us avoid programming errors. TDD does so by making us write small, automated tests, which eventually build up a very effective alarm system for protecting our code from regression. You cannot add quality into software after the fact, and the short development cycle that TDD promotes is well geared toward writing high-quality code from the start.”

You can read more about TDD on MSDN, but briefly, TDD states that you drive the development from the tests. Therefore, you need to write the tests first, before you write even a single line of code, and then use those tests to ensure your code meets the requirements. For example, suppose you wanted to write a method to calculate factorials. First, you’d write a test that would ascertain whether the return value from your factorial-calculation method is a valid factorial:

   public void TestFactorial()   {      int expected = 6;      int actual = MyClass.CalculateFactorial(3);      Assert.AreEqual(expected, actual, "Factorial is Invalid");      expected = 1;      actual = MyClass.CalculateFactorial(0);      Assert.AreEqual(expected, actual, "Factorial is Invalid");   }

Assert is a static class available in the Microsoft.VisualStudio.TestTools.UnitTesting namespace. You use the Assert.AreEqual method to test whether two specified values are equal?it returns false when the two values are not equal. With the test in place, you can code the factorial-calculation method:

   class MyClass   {      public static int CalculateFactorial(int Number)      {         if (Number < 0) return -1; // -1 = undefined         if (Number <= 1) return 1;         int fact = 1;         for (int i = 0; i < Number; i++)         {            fact = fact * (Number - i);         }         return fact;      }   } 

Now that you have a basic understanding of TDD, you can explore what VSTET offers for developers using TDD?VSTET provides almost everything you need to test an application within the VS 2005 IDE. Almost, because of the limitations mentioned toward the end of this article. VSTET lets users create, manage, edit and run tests. It even allows you to store the test results.

Types of testing supported by VSTET
VSTET supports the following test types:

  • Unit Tests: As the name implies, this type of test is intended to test a specific unit of your code. VSTET ships with a built-in unit testing framework called Microsoft.VisualStudio.QualityTools.UnitTestFramework, which includes a variety of namespaces, classes, and interfaces that you can use to write, execute, and report on unit tests.
  • Web Tests: A Web Test lets you record sequences of user interactions and navigation between pages in a web application. You can then reuse these recordings to test your application.
  • Manual Tests: This is the simplest type of testing. You need to execute the application and run the test cases one after the other to ensure that the preconditions, post conditions and the results actually meet your requirements as defined in the test cases.
  • Load Tests: You use load tests to run unit tests and/or web tests with some predefined parameters for performance testing.
  • Ordered Tests: This type consists of a list of tests intended to run in a specific order. Note that you cannot include a load test in the ordered test list.
  • Generic Tests: This type lets you use third-party tools or executables as tests in VSTET. For example, you could plug in existing tests from other sources or a custom executable that ran tests into VSTET using this type of test. After you wrap your existing test, executable, or third-party tool inside a generic test, VSTET treats it like any other test type.

Structuring the Solution
To see how to implement the various test types using VSTET, this article uses a downloadable web site example that requires user registration and login. You can see the solution's structure and components in Figure 1.

?
Figure 1. The WebTest Solution: The projects in the sample solution include a simple web site, a data access layer, and several test projects.

The example solution consists of six projects.

  1. WebTest: This project contains the UI elements for the web site, including a default login page and a home "welcome" page.
  2. WebTest.BizObjects: This project holds the required business objects. The User.cs file contains code that defines a User object.
  3. WebTest.DAL: This is the data access layer. The UserDAL class contains various method implementations supported by the User class.
  4. WebTest.DAL.Interfaces: This project contains the interfaces. IUserDAL defines a list of operations supported by the User class.
  5. WebTest.DAL.UnitTests: This project contains unit tests for testing the WebTest.DAL layer.
  6. WebTest.WebTest: This project contains web tests for testing the UI portion of the WebTest project.

Implementing Unit Tests with VSTET
When designing unit tests it's good practice to have separate unit-testing projects for each layer in your application. A discussion of implementing a data access layer is beyond the scope of this article, but however you create one, you'll need to test it. Here's an example of creating a unit test to test the data access layer of an application.

First, create a new project and name it "WebTest.DAL.UnitTests." When you do that, VSTET automatically creates a test class called UnitTest1 in a file named UnitTest1.cs. You can use that class to test the data access layer. Rename the file to UnitTest.cs, and copy the code from Listing 1 into it. Notice that the UserDALTests class is decorated with a TestClass attribute?implying that it is a class used for testing other classes.

The UserDALTests class uses an email constant string to uniquely identify a particular user for testing user operations.

   private const string Email = "[email protected]";   
Author's Note: You could just as easily store the email string in a configuration file, which would make it easier to test with different users.

The SetUpTestUser() method creates a user record used in all the unit test class methods.

   [ClassInitialize()]   public static void SetUpTestUser(TestContext testContext)   {      try      {         User user = new User();         user.Name = "Test";         user.Password="[email protected]";         user.Email = Email;            UserDAL userDAL = new UserDAL();         userDAL.CreateUser(user);                         }      catch (Exception ex)      {         Assert.Fail(ex.Message);      }   }

Note that SetUpTestUser() is decorated with the ClassInitialize attribute, which ensures that the code inside this method gets executed before the first test in the class executes.

The other methods in UserDALTests are fairly self-explanatory, so this article won't discuss them in detail (see the downloadable code for details), but briefly, each test method in the UserDALTests class tests a similarly named method in the UserDAL class. For example, TestCreateUser tests the CreateUser method,TestGetUser tests the GetUser method, and TestGetUsers, TestUpdateUser, and TestDeleteUser test the GetUsers UpdateUser and DeleteUser methods, respectively. Finally, the ClearTestUser method deletes the test user record created by SetUpTestUser. Note that this method is marked with the ClassCleanup attribute, which ensures that code in this method gets executed after all the tests in the class have been executed.

Author's Note: The test methods marked using the [TestMethod] attribute should be non-static and public. Moreover, they should not return any value, nor can they accept any parameter.

When you design your unit test classes in this manner, it's far easier to initialize and clean up any resources that the unit tests require for testing. For example, if you're writing unit tests for database operations, you might create a dummy record in a method marked with the [ClassInitialize] attribute, use it in the class methods to test the database operations, and finally, delete it within a method marked with the [ClassCleanup] attribute.

Exploring TDD Support in VSTET
After installing VSTET, you will find a new menu item named "Test." That menu provides five windows that let you mange test runs and results.

  1. The Test View window displays a list of all the tests in the solution (see Figure 2), including the name of each test and which project it belongs to. This window also allows you to filter and group tests.

    You can run or debug a test by selecting it and then selecting Run from the Test View window.

  2. ?
    Figure 2. Test View Window: This window shows a list of all the tests in the solution.
    ?
    Figure 3. Test Manger Window: This window provides a configurable way to view all the tests in a solution.
  3. You can use the Test Manager window (see Figure 3) to organize tests into different lists. The window supports filtering and grouping. You can also use the Test Manager window to import and load test metadata files?XML files with a .vsmdi extension. VSTET automatically creates a test metadata file when you add a test project to your solution.
  4. The Test Results window (see Figure 4) displays test outcomes, and lets you publish, import, or export test results. You can also filter and group results in this window.
  5. ?
    Figure 4. Test Results Window: This window displays the result of a test run, the test name, and any error messages.
  6. As shown in Figure 5, the Code Coverage Analysis window displays an analysis if you have enabled it for the test.
  7. ?
    Figure 5. Code Coverage Analysis Window: If enabled, the analysis appears in this window, showing which blocks are covered and not covered, and the percentage of each relative to the entire project.
  8. The Test Run window displays details about active, queued, and completed test runs (see Figure 6).
  9. ?
    Figure 6. Test Run Window: This window shows active, queued, and completed test runs.

As you can see, VSTET's built-in TDD support is comprehensive. Running standard tests is straightforward, but there's specialized support for implementing and running Web Tests as well.

Building Web Tests
A web application is a conglomeration of individual requests, interactions, and responses. Therefore, to test it well, you need to be able to simulate a series of such requests, interactions, and responses. Web Tests let you record requests, user interaction, and navigation from one web page to another so you can later execute the sequences as tests to validate the build. Recorded, replayable Web Tests can save you a lot of time and help in doing regression (verifying the fixed bugs), smoke (making sure that new changes do not cause the basic functionality to fail), or sometimes full-build testing.

Suppose you have the following test case:

   Summary: Test the User login   Steps to execute the test:     1. Navigate to http://webtest/default.aspx   2. Enter user name and password   3. Click the Login button   Expected result: Users should be directed to       the home page:       http://webtest/home.aspx,       and see a welcome message. 

Here are the steps to record a Web Test:

  1. Create a new test project and name it WebTest.WebTests.
  2. Right click and select the "Add a New Test" option.
  3. Next, select the "Choose Web Test" option from the displayed list of templates.
  4. Name the test UC1 _TestLogin.webtest.
?
Figure 7. Executing a Web Test: Select the test you want to run, and click the green Play button on the top left-hand side of the Web Test toolbar.

When you've completed those steps, VSTET launches an IE browser window. Type the URL of the web site for which you want to record the Web Test?in this case http://localhost/Webtest. Enter a user name and password and click the Login button, and then close the browser window. That's it!

To run the Web Test you just created, open it and click the green Play button on the top left-hand side of the Web Test toolbar (see Figure 7).

Author's Note: If you are hosting the web site on a file server, make sure that you have the ASP.NET development server (Cassini) running on one of the ports. Replace the port number in the Web Test requests with the port number that you are using.

The Web Test will execute, sending each of the requests you recorded using the Web Test recorder in their original sequence. The test will record the response time of each request-response cycle, and the size of the response. It will use the appropriate protocols and handle passing any parameters.

?
Figure 8. Web Test Result: In this Web Test Result you can see each requested URL along with the response status, time, and size.

As shown in Figure 8, this Web Test result example consists of three HTTP responses. The Response tab shows the exact response retrieved from the server, including the status, response time, and size of the each request. The Request tab shows the full request sent to the server, including parameter values.

Web Test Structure
Web Tests consist of rules and parameters that let you manipulate the test so it does exactly what you want.

Extraction Rule
Extraction rules are primarily used for extracting the data from one response and using it as an input to another request. If you expand the first request in the Web Test, you'll see an Extraction Rules folder that contains one item: "Extract hidden fields." This is an extraction rule created by the web recorder for extracting the View state, which it stores as a hidden field and feeds to the next page (Home.aspx).

Think Time
If you try to view the properties of the WebTest request, you will notice that there is a "Think Time" parameter. Think time is time that elapses before a user takes an action that causes the web test to generate the next request. Think time does not include the time required for a page to load.

Form Post Parameters
The Form Post Parameters contain any parameters posted back to the page, which may include control values, Viewstate, the EventTarget, event arguments etc.

Validation Rule
At this point, you can see from Figure 8 that the Web Test is running fine, but just because it ran doesn't mean that it's running according to the test case rules. You need to validate the test results. Remember, the test case "Test the User login," states that "After clicking on the Login button, users should be directed to the home page, http://webtest/home.aspx, which displays the welcome message." In other words, the test case should pass only if it meets the use case conditions.

?
Figure 9. Adding a Validation Rule: The figure illustrates how to add a validation rule for a required attribute value.

You can use Validation Rules to verify both conditions. To create a Validation Rule to verify whether users who logged in were successfully directed to Home.aspx, right-click the second request in the Web Test Result, and select "Add validation rule." You'll see the Add Validation Rule dialog. Select the "Required Attribute Value" item from the left side and fill in the values on the right as shown in Figure 9.

This validation rule verifies that the response to the second request should contain a

tag with an id attribute of "form1" and an action attribute of "Home.aspx:"

   

In other words, this rule will fail if users are not directed to Home.aspx.

?
Figure 10. Validating Content: Using the Find Text rule, you can verify that the browser has loaded content containing specific words or phrases.

Similarly, to verify that users saw the welcome screen, right-click the third request and select "Add validation rule." Select the "Find Text" item from the left pane, and then in the right pane, fill in the values shown in Figure 10.

Coded Web Tests
Coded Web Tests are useful when simply following a prerecorded path isn't sufficient for verification, and you need to plug in your own custom logic to generate Web Test Request properties. For example, using the already-recorded Web Test example from the preceding section, suppose you want to analyze how the login page behaves if 1000 users try to login at the same time. You could simulate that by running the existing test inside a Coded Web Test class and looping 1000 times.

You can create a Coded Web Test from an existing recorded Web Test. To do that, open the UC1 _TestLogin.webtest and click the "Generate Code" button on the Web Test toolbar. Name the class CodedWebTest.cs and click OK. That generates a class file so you can see and modify the code.

VSTET's support for Coded Web Tests makes web testing extensible, and simplifies the process of mapping real-world test cases to Web Tests.

VSTET Limitations
With all the attractive features available in VSTET for Test-Driven Design, there are still a few that you might wish were available:

  • VSTET does not support NUnit tests. Converting NUnit tests to Visual Studio unit tests takes time?and sometimes isn't possible. But there is a workaround; see http://www.codeplex.com/NUnitForVS for further details.
  • The VSTET web recorder is not capable of capturing JavaScript requests. You can use the Fiddler tool for that.
  • VSTET tests do not support inheritance. So you can't write a base test and inherit from it.

Used in conjunction with properly planned code reviews, test-driven development can prove beneficial in designing and implementing high quality applications that conform to the quality standards and meet the stated requirements. Visual Studio Team Edition for Testers builds on the familiar VS.NET IDE by adding robust support for TDD, letting you define, execute, manage, and view test reports. These features promise to reduce development time, code complexity, and post-deployment bugs.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: