We're nearing the end of our first Agile iteration and things are looking pretty good. Development is proceeding at a brisk pace and a lot of cool new features are being added to Geocortex Essentials. These new features appear to be pretty solid and the existing code-base has held together well. Everyone is writing unit tests and apart from some scheduling issues, things have actually gone quite well.

As many of you know, one of the Agile practices is Test-Driven Development. The idea simple, yet really changes the way you write code. The idea is to write tests in parallel with the feature you are developing. When the feature is complete, all of your unit tests pass and you're left with a high quality feature together with a high-quality set of unit tests. If the tests are comprehensive, the developer can have a high level of confidence that his code is very high quality.

We organize our unit tests so that we have one test fixture per public class and one test method per public or protected method. For example, if we have a class called DataStore, we would also have a class called DataStoreFixture. Similarly, if DataStore has a method called ReadXml, DataStoreFixture would have a corresponding test method called ReadXml. We keep test fixtures in separately compiled assemblies in a subdirectory called Tests, beneath the project containing the classes we are testing. The test project references the project being tested.

We test the coverage of our unit tests using TestDriven.net. Its pretty easy to get to 80% coverage without too much effort but its fun to try and get as close to 100% coverage of possible. In practice, anything over 95% is excellent. To achieve this, we must test all of our code; code that actually does the work, together with any code that throws exceptions. Testing exceptions can be a challenging and can lead to some very repetitive patterns.

One approach to testing exceptions would be to call a method, passing it arguments that induce an exception and wrap that call in a try-catch block. If the exception does not fire, then the test fails. If the methods you are testing have long parameter lists, then you will end with a lot of try-catch blocks. Another method would be to use NUnit's [ExpectedException] attribute. The idea is that you decorate a test method with [ExpectedException] and if that method runs to completion without throwing that exception, then the test fails. This is an interesting solution but it would require writing one test method per exception we are testing which could be quite a large number of methods.

The solution I came up with was to write a method called AssertException. AssertException takes an object, the name of a method on that object, an exception that we're expecting to be thrown, and a set of arguments to pass that object and then asserts that that exception is fired. For example,

  AssertException("AddUsersToRoles", roleProvider, typeof(ArgumentException), null, new string[0]);

Here is my implementation of AssertException. It uses reflection to call the method being tested and the params feature of C# to pass that method its parameters.

   public static void AssertException(string methodName, Object target, Type exceptionType, params object[] methodParams)
   {
    try
    {
      MethodInfo methodInfo = target.GetType().GetMethod(methodName);
      methodInfo.Invoke(target, methodParams);
      Assert.Fail(exceptionType.Name + " expected");
    }

    catch (Exception e)
    {
      if (e.InnerException != null)
      {
         if (e.InnerException.GetType() != exceptionType)
        {
          Assert.Fail(exceptionType.Name + " expected");
        }
      }

      else
      {
        throw;
      }
    }
  }

Enjoy.