Sunday, September 03, 2006

Unit Testing in .NET

I love unit testing. Ever since I got that first green light I was hooked. I love knowing that my code's behaviour is correct even though it has never been run in the context of a "real" application. I love knowing that I can run old tests to ensure that I haven't inadvertently broken code. But most of all, I love writing unit tests before I write my code (TDD [^]) and making positive changes to my APIs and behavioural assumptions before I even implement the code. What I hate about unit testing is the "tacked-on" feeling it has. Developer's need to choose between several different unit testing frameworks (NUnit, csUnit, mbUnit or VSTS's framework) and several different mocking frameworks (Rhino Mocks, NMock, TypeMock.NET). What's more, no combination of frameworks and techniques I've found allows you to perform close to 100% code coverage without hacking your code base. Inevitably I've found the need to expose internal members for testing purposes only. In other cases I've found mock libraries limited in what they can mock because of the fact that they typically generate a separate assembly at runtime. All this hackiness has lead me to believe that unit testing should be a platform feature. .NET should allow developers to specify unit test implementations for their classes. Unit tests would have unadulterated access to the members of the unit under test. In addition, the CLR should provide mocking services when running in this mode. Consider:
public abstract class Foo
{
 public void DoSomething(IDbConnection connection)
 {
  if (connection == null)
  {
   throw new ArgumentNullException("connection")
  }
  
  DoSomethingCode(connection);
 }
 
 internal abstract void DoSomethingCore(IDbConnection connection);
}
My holy grail is to be able to unit test this class without sacrificing encapsulation and without the need for implementing custom mock classes. So far I have been unable to do so. I must admit, I have never tried TypeMock.NET and will do so soon. If the CLR had intrinsic unit testing concepts, you might be able to simply tag the class as follows:
[UnitTest("Namespace.FooTest")]
public abstract class Foo
{
 //as before
}
By virtue of this attribute, the CLR might grant FooTest full access to Foo's members, perhaps only when running the CLR in a special unit test mode. In addition, running in this mode would allow unit tests to generate dynamic mock implementations and set expectations on those mocks. These mocks would not be limited in capabilities as are current mocking libraries (eg. Rhino understandably can't mock sealed classes or non-virtual members). Obviously I am just spewing out ideas here. I would love to see MS take .NET down such a path - a path where unit tests are first class citizens. I shall continue on my quest for the holy grail by taking a look at TypeMock.NET's abilities.

3 comments:

Anonymous said...

So what is the verdict, what do you think of TypeMock?

Trumpi said...

Hi Kent

I really like your suggestion about unit tests being first class citizens in the .NET framework. It will, of course open many possibilities, including the ability to ignore constructs such as sealed, (non) virtual, etc.

Chris Holmes said...

Kent,

There's actually a solution to testing private and internal methods in .NET. Reflection. In case your blog doesn't allow links, check out my post on this at chrisholmesonline.com.

Link to article