OdeToCode IC Logo

Unit Testing and Refactoring in VS 2005 Beta 2

Wednesday, August 17, 2005

I started some new work on a .NET 2.0 project recently and decided to dive headfirst into the unit testing features in 2005. The auto-generated tests seem to have a fundamental flaw and I’d recommend avoiding them (at least in beta 2).

It’s easy to put the cursor on an existing class, right-click and select “Create Tests…”. Visual Studio will generate a boatload of code at this point, including a unit test class with a test method for each method and property on the target class.

The stubbed out test methods are setup to work through an accessor class. If you create an Account class, and use the “Create Tests…” option, Visual Studio creates an AccountAccesor class.

The accessor classes will proxy calls to the real object using reflective techniques, i.e. with an Invoke call. This approach allows you to test protected and private members of a class as if they were public members. The merits of testing non-public members of a class are debatable, but the layer of indirection an accessor adds takes all the fun out of refactoring.

One of the many benefits of the refactor feature is that you can change the name of a method or class and feel confident that the IDE can manage the aftermath. There is no need to do a global search and replace by hand – the IDE takes care of cleaning up.

Let’s say you want to rename your Account class to CAccount because you miss programming in MFC (in which case I suggest you look for professional help). The refactoring will not change the code in your unit tests, because the unit tests are using the accessor class instead of the real class. The instantiation of the accessor would look something like the following (except it’s actually a lot uglier):

_accountAccessor accessor = new _accountAccessor(target);

Of course, the accessor class needs to create a real instance of the Account class to test, but because it creates an instance in a late bound manner. The Account class type is only referenced as a string, like the following (except it’s actually a lot uglier).

protected static PrivateType m_privateType =

    new PrivateType("AssemblyName", "Namespace.Account");

The refactor feature can't make any changes to your unit tests because it doesn't know where you were using the Account class. The next time you run your tests you'll have a pile of exceptions about missing methods and classes.

You can regenerate just the accessor classes, but you'll still have a mess to clean up by hand.

I’m not sure what the generated tests will look like in the RTM versions of Visual Studio 2005 / Team System (or even what versions will support unit testing), but I’m staying away from the auto-generated tests in beta 2.

Something is fundamentally wrong if a testing feature makes refactoring more difficult ... or am I missing something?