TDD and test generation in VS 2005 can be annoying and tricky if you don't watch out
- VS 2005 is cool. You get great Intellisense and there's a even a nice refactoring that lets you create method stubs when you write code that uses a method that does not exists.
- VS 2005 also has a great feature for unit testing that allows you to create unit tests for existing classes by simply Right clicking on the classes ans selecting "Create tests".
- When you do this VS 2005 also adds another feature in the unit testing framework that creates a wrapper object for your test class. This wrapper object uses reflection to exposes any public and PRIVATE methods of your tested class as if they were public (the merits of this approach can be debated to death, no doubt. Personally, I'm against it). That means all your tests (that were generated) will use the *wrapper* object in the code, and not the actual production code.
Now - couple all these three features together and what do you get?
Imagine you just generated a test for your class, and you want to drive the features of this class in a test-driven manner, that is, you want to first write tests that fail, and only then write the production code to make them work.
So, you write a line of code in a new test that uses the wrapper object that was generated for you by the test framework. Suppose you want to create a method named "add" on a calculator object. your code could look like this:
[TestMethod]
public void TestAdd()
{
CalculatorWrapper calc = new CalculatorWrapper();
int result = calc.Add(1,2);
Assert.AreEqual(3,result);
}
obviously this test won't compile, but! now we can use feature number 1 in the above list: with right click on the "calc.Add" line and select "implement stub". What do you expect should happen?
Yeah. That wouldn't work. Because the actually stub would be added to the *wrapper* object that was generated for you, and not to the actually class. So now you need to manually add the method to the class or not use the wrapper object at all.
Let's say you want to continue using the wrapper object, you then manually add the empty method to the class. The test will still fail! Remember that you implemented the stub automatically in the wrapper object? the default template for an empty method stub throws a System.NotimplementedException. Yes, you now need to manually added code in the wrapper object to make sure it calls the right method on your actual tested calculator object. since all that code uses reflection, that could get messy fast.
Let's say you want to continue using the wrapper object, you then manually add the empty method to the class. The test will still fail! Remember that you implemented the stub automatically in the wrapper object? the default template for an empty method stub throws a System.NotimplementedException. Yes, you now need to manually added code in the wrapper object to make sure it calls the right method on your actual tested calculator object. since all that code uses reflection, that could get messy fast.
In short - TDD and automatically generated wrapper objects don't mix too well in the current versions of VS 2005.
Beware. You usually do TDD and should do it on the real object. Wrapper objects should stay where they belong - on tests that you generated.
If you think I'm right -
go and vote on this missing functionality in the product feedback site
So what happens if you DO want to write tests for private methods? well, than you can use the wrapper, but make sure you re-generate it every time you refactor your code - private methods change *all the time* - your tests will break *all the time* too.