VSTS comes with many tools integrated in it for the developers & testers and also for architects and managers. The unit testing tool that comes with the Visual Studio 2005 enables the developers to generate the test classes and methods. Team Test does not provide tools only for developers but it provides tools for testers as well. The other feature of the Team Test is the ability to load data from the database to test the methods. Here we will see an example for creating unit tests and with exceptions as well.
Let me walk through how to create unit tests. Let's take an example of creating an assembly with an Employee class and method for adding an Employee with his/her First Name, Last Name and Date of Birth. Create a new class library project named "VSTSEmp". You can see the checkbox option "Create directory for solution". This checkbox is checked by default. This enables us to create the test project in a separate directory. If the checkbox is deselected, the test project will get created in the VSTSEmp project directory itself. Lets leave the checkbox option selected.
The new project contains a class file with the default name as "Class1.cs". Let's rename the class file as "Employees.cs" which will also rename the class name to Employees. Include the constructor for the Employee class with three parameters as first Name as string, lastName as string and dateofBirth as datetime.
Now we will see how to create the test class and test method for the employee class and its constructor. Anywhere on the employee class right click and choose the option "Create Unit Tests...".
Selecting the menu option "Create Unit Tests..." will display a dialog for generating the unit tests as different project. Lets give the name for the test project as "VSTSEmp.Test". Enter this value in the dialog box. Make sure "Create a new Visual C# test project..." option is selected in the output project options as we are using C# for our test.
The test project creates with 2 default files as "AuthoringTests.txt" and "EmployeesTest.cs".
- The "AuthoringTests.txt" file gives information about authoring the tests and different types of tests that we can perform using VS 2005 team test.
- The EmployeeTest.cs is the generated test class file for the Employee class by which we can include or generate test methods for all the methods of the Employee class
The generated test project contains references to "VSTSEmp" project against which the test project is created and the Microsoft.VisualStudio.QualityTools.UnitTestFramework which is the testing framework assembly for the test engine to execute the test project. Following is the generated test class and the test method for the constructor with the default implementation.
Listing 1
// The following code was generated by Microsoft Visual Studio 2005.
// The test owner should check each test for validity.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Text;
using System.Collections.Generic;
using VSTSEmp;
namespace VSTSEmp.Test
{
/// <summary>
///This is a test class for VSTSEmp.Employees and is intended
///to contain all VSTSEmp.Employees Unit Tests
///</summary>
[TestClass()]
public class EmployeesTest
{
private TestContext testContextInstance;
/// <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 Employees (string, string, DateTime)
///</summary>
[TestMethod()]
public void ConstructorTest()
{
string firstName = null; // TODO: Initialize to an appropriate value
string lastName = null; // TODO: Initialize to an appropriate value
DateTime dateOfBirth = new DateTime(); // TODO: Initialize to an appropriate value
Employees target = new Employees(firstName, lastName, dateOfBirth);
// TODO: Implement code to verify target
Assert.Inconclusive("TODO: Implement code to verify target");
}
}
}
There are two important attributes which identified the Test class and test methods. The test class is identified with the attribute "TestClassAttribute" attribute. The test methods in the test class are identified with the "TestMethdAttribute" attribute. Both these attributes are available in Microsoft.VisualStudio.QualityTools.UnitTestFramework. Team test uses reflection to find the test assembly and then finds all the test classes using the test class attribute. After finding the test class the team test finds all the test methods using the Test Method attribute. The test method (ConstructorTest()) instantiates the target Employee class before asserting that the test is inconclusive (Assert.Inconclusive()). The Assert.Inconclusive() indicates that the correct implementation of the method is missing. Lets update the ConstructorTest() method so that it checks the initialization of the employee firstName and dateofBirth. We have not yet created the fields or properties for the FirstName, LastName and DateofBirth. Before updating the test method we have to create these properties in the Employee class to avoid compile errors.
Asserts
Here the checks are done using the Assert.AreEqual<T>() method. The assert method also supports an AreEqual() method without Generics. The generic version is always preferred because it will verify at compile time that the types match.
Let's run the test with whatever implementation we have. The implementations are not yet over but let's proceed to testing. We need to run the test project to run all the tests. Just right click the test project and make it the Startup project. Using the Debug-> Start (F5) menu item begin running the test project.
After running the project the Test Result window appears. The result shows one failed and nothing else because we have only one method for testing. Initially the result will be shown as "pending" then "In progress" and then it will display "Failed". You can add/remove the default columns in the test result window using the menu options
To see additional details on the Constructor test result, just double click on the error message. The ConstructorTest[Results] widow opens up with more information on the error.
Now Lets test for an exceptions using the "ExpectedExcpetionAttribute". Below code shows two methods which checks for null or empty string value for the employee First Name. This value null or empty value to the constructor throws the exception of type "ArgumentException".
TestMethod]
ExpectedException(typeof(ArgumentException),
"Null value for Employee First Name is not allowed")]
public void EmployeeFirstNameNullInConstructor()
{
Employees Employee = new Employees(null, "Kumar", System.DateTime.Today());
}
[TestMethod]
[ExpectedException(typeof(ArgumentException),
"Empty value for Employee First Name is not allowed")]
public void EmployeeFirstNameNullInConstructor()
{
Employees Employee = new Employees("", "Kumar", System.DateTime.Today());
}
Notice that the above code does not have any try catch block like normal exception handling. The code contains one attribute ExpectedException which includes one parameter for the type of exception and the other parameter for the error message. Now when you execute the test project, the framework will expect an argument exception to be thrown. If not, the test will fail. Now update the Employee class to provide the functionality the tests are checking for. Below is the updated code.
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
if (value == null || value.Trim() == string.Empty())
{
throw new ArgumentException("Employee First Name cannot be null or Empty");
}
_firstName = value;
}
}
Now run the test and make sure the implementation is correct.