Thursday, January 26, 2012

Structuring Unit Tests

Phil Haack wrote an article entitled "Structuring Unit Tests" (I highly recommend reading it) and it started us talking about how we could adopt this method of test structuring in our projects. The basic structure is a test class that contains test classes for each system under test.

We are a test-first shop and use MSTest as our testing tool of choice. So, step 1, write some tests that follow the structure (I am just going to reproduce Phil’s example using MSTest):

[TestClass]
public class TitleizerTests
{
[TestClass]
public class TheTitleizerMethod
{
[TestMethod]
public void ReturnsDefaultTitleForNullName()
{
//test code
}

[TestMethod]
public void AppendsTitleToName()
{
//test code
}
}

[TestClass]
public class TheKnightifyMethod
{
[TestMethod]
public void ReturnsDefaultTitleForNullName()
{
//test code
}

[TestMethod]
public void AppendsSirToMaleNames()
{
//test code
}

[TestMethod]
public void AppendsDameToFemaleNames()
{
//test code
}
}
}

Right away we noticed two problems. When you use the keyboard shortcut Ctrl+R, C all tests in the class are run. This works great using this structure because it runs all tests in the SUT class allowing you to isolate the scope of tests to run. The problem is when you want to run all tests in the top level class. If you try Ctrl+R, C at the top level, all tests in the namespace get run. This was easily solved by creating a unique namespace for the test class to reside in:

namespace TestStructure.UnitTests.TitleizerTestContainer
{
[TestClass]
public class TitleizerTests
{
[TestClass]
public class TheTitleizerMethod
{
[TestMethod]
public void ReturnsDefaultTitleForNullName()
{
//test code
}

Now we can run all tests in the class without issue.

The second problem is code duplication. If some setup is required for my class before I can perform my tests, I have to repeat it for each class because nested classes do not have access to their parent members. Our solution to this is to make all of the children inherit from the parent test class like this:

[TestClass]
public class TitleizerTests
{
protected Titleizer target;

[TestInitialize]
public void Init()
{
target = new Titleizer();
}

[TestClass]
public class TheTitleizerMethod : TitleizerTests
{
[TestMethod]
public void ReturnsDefaultTitleForNullName()
{
//act
string result = target.Titleize(null);

//assert
Assert.AreEqual(result, "Your name is now Phil the Foolish");
}

[TestMethod]
public void AppendsTitleToName()
{
//act
string result = target.Titleize("Brian");

//assert
Assert.AreEqual(result, "Brian the awesome hearted");
}
}

This is obviously a contrived case where no actual setup is required, but now the TestInitialize method will run before each test in my child classes.

Plus the test are much easier to read:

image

image

We are just stating to experiment with this test structure, but so far it looks very promising.