Wednesday, November 14, 2007

Introduction
In my last post I gave a very brief introduction to the Test-Driven Development (TDD) process and demonstrated a very simple project in Visual Studio 2008 that showed how to create tests for a class. In this post I will introduce more of the tools and classes available in Visual Studio 2008.

In this post I will look at:

  • The TestContext class.
  • The Attributes available for defining test classes and methods.
  • The Assert class.
  • Private objects
  • Debugging tests within Visual Studio 2008.

The TestContext class
The TestContext class allows you to get a handle on the context in which the test is being executed. From this you can obtain useful information. For example when testing an ASP.NET application the TestContext class allows you to get a handle to the Page class. From this you will then be able to get a handle to the various controls contained on the page, this is an example I will expand upon in future posts.

 When you use the wizards built into Visual Studio 2008 to generate your unit test classes a TestContext property and corresponding member variable will be automatically added to your class. The runtime will take care of setting this property for you, therefore freeing you to simply use the TestContext as you need. The code snippet below shows the definition of the TestContext property and the corresponding member variable, this is not code you will have to write unless you are writing your test manually.

        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;
}
}

Attributes for Testing
All classes related to unit testing is Visual Studio 2008 are located in the namespace Microsoft.VisualStudio.TestTools.UnitTesting. I’ve already introduced two attributes in my last post the TestClass and the TestMethod attributes, these are the most common attributes that you will need for every test you write, the list below illustrates some of the other attributes that you may find useful when writing tests.

AssemblyInitialize and AssemblyCleanup
Allows you to identify methods that should be called before any tests in an assembly are executed and after all tests have completed.
 

ClassInitialize and ClassCleanup
Similar to the AssemblyInitialize and AssemblyCleanup except these are used to identify methods that are called before and after all tests in a test class are executed.

TestInitialize and TestCleanup
Again similar to AssemblyInitialize, AssemblyCleanup, ClassInitialize and ClassCleanup these attributes allow you to define methods that should be called before and after each individual test is executed.

Description
This attribute allows you to include a descriptive string that can then be listed in the test results window. The code snippet illustrates applying this attribute to the TestAddPositiveNumbers methods from my previous post and the screen shot shows how the description is displayed in the test results window. This can be a useful addition to helping convey the reasons for having a test but personally I would recommend striving to create meaningful names for your tests methods, avoid using names like ‘Test1’ for your test methods.

        [TestMethod]
[Description("Try and add two positive Numbers (2+2) and ensure that the answer is 4")]
public void TestAddPositiveNumbers()
{
Calculator cal = new Calculator();
int result = cal.Add(2, 2);
Assert.AreEqual(4, result);
}



Note: By default the description column is not displayed in the test results window, to display this column right click on the test results window and select “Add/Remove Columns…” this will display the following dialog that allows you to select the columns you wish to display.

 




ExpectedException
A very useful attribute this allows you to tell the runtime to expect a particular exception when running a test. When conducting unit tests you should be testing both normal and erroneous conditions, so you should pass invalid data to your methods and use unit tests to verify that your method can handle the error conditions appropriately. This is where the ExpectedException attribute can be useful. Normally if an exception occurs while executing a tests this will cause the test to fail, however telling the runtime to expect the exception will allow the test to pass, provided the exception raised match the type expected.


To illustrate this I have added a divide method to the calculator class from my last post. One of the tests and the implementation of the divide method are shown below.

HostType
This attribute identifies the test as being run outside of the current environment. For example specifying the string “ASP.NET” as the parameter to this attribute allows you to run tests in the ASP.NET development server. This is an attribute I will explore in more depth with later posts when I’ll be looking at testing an ASP.NET application.

For more information on the attributes available and their usage see the MSDN documentation.

The Asset Class
Central to helping you construct unit tests the Assert class provides a set of static methods that evaluate a Boolean condition. If the condition evaluates to true then the assert passes otherwise the assert fails and the unit test will be listed as a fail in the test results window. This is a list of some of the methods the Assert class provides, for more details on these check out the MSDN documentation. At this stage I’m only listing them to make you aware of their existence, in later posts I will use these as I need to illustrate points.

  • AreEqual
  • AreNotEqual
  • AreNotSame
  • AreSame
  • Fail
  • IsFalse
  • IsInstanceOfType
  • IsNotInstanceOfType
  • IsNotNull
  • IsNull
  • IsTrue

Private objects
In the past when I’ve been writing unit test I have been trying to test a class which relies on another class which has an instance of this class as a private field, and in keeping with the ethos of unit testing by testing each class in isolation this has presented me with a dilemma, do I test the two in conjunction, or do I expose some means of allowing the field to be set. Neither of these has ever proved to be an ideal solution, testing in conjunction is a big no and writing extra code to make a field publicly available doesn’t sit well, if there was no need for the outside world to know of this field before then it should be private. With private objects you now have the ability to solve both of these problems. My next post will give an example of using private objects.

 Debugging tests in Visual Studio 2008
Debugging unit tests with Visual Studio 2008 is straight forward simply follow these steps: 

1.  Open your solution that contains the test projects

2.   Open the class that contains the test you wish to debug and add a breakpoint to that test.

3.    Select Test -> Debug -> All Tests in Solution. The keyboard short cut to debug all tests is Ctrl+R Ctrl+D

 An alternative to debugging all tests in the solution is to use the test results window to select the tests you wish to debug. Then click on the drop down menu on the Debug button on the test results window toolbar and select “Debug Checked Tests”.


Conclusion
In my previous post I identified the TDD process and in this post I have built on this to introduce many of the features available in Visual Studio 2008 to facilitate unit testing. In subsequent posts I will get more practical with code examples that show how to use these features. The first of these will introduce the use of private objects with some example code.