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.
Implementing Unit Tests with VSTET
- WebTest: This project contains the UI elements for the web site, including a default login page and a home "welcome" page.
- WebTest.BizObjects: This project holds the required business objects. The User.cs file contains code that defines a User object.
- WebTest.DAL: This is the data access layer. The UserDAL class contains various method implementations supported by the User class.
- WebTest.DAL.Interfaces: This project contains the interfaces. IUserDAL defines a list of operations supported by the User class.
- WebTest.DAL.UnitTests: This project contains unit tests for testing the WebTest.DAL layer.
- WebTest.WebTest: This project contains web tests for testing the UI portion of the WebTest project.
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 = "firstname.lastname@example.org";
|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.
method creates a user record used in all the unit test class methods.
public static void SetUpTestUser(TestContext testContext)
User user = new User();
user.Name = "Test";
user.Email = Email;
UserDAL userDAL = new UserDAL();
catch (Exception ex)
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
tests the GetUser
method, and TestGetUsers, TestUpdateUser, and TestDeleteUser test the GetUsers UpdateUser
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]
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.
- 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.
|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.||
- 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.
- 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.
|Figure 4. Test Results Window: This window displays the result of a test run, the test name, and any error messages.|
- As shown in Figure 5, the Code Coverage Analysis window displays an analysis if you have enabled it for the test.
|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.|
- The Test Run window displays details about active, queued, and completed test runs (see Figure 6).
|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.