Saturday, February 14, 2009

What is unit testing and why should we do it?

Throughout the lifecycle of any project, many types of testing should and are done. Usability testing is needed to check if the user interface is easy to use and understand. Security testing is essential for software which processes confidential data and to prevent system intrusion by hackers. Performance of load testing checks to see if the software can handle large quantities of data or users. This is generally referred to as software scalability. Each of these types performs an important role. One type of testing that is often overlooked it known as unit testing.

Unit testing is the practice using small bits of code to exercise code that you have written. In many ways it is something that we have all been doing all along. Every time you single out a specific method and test it intensely to make sure it works as expected you are in a way unit testing your code. This is ok, but wouldn’t it be nice if you could re-execute these tests over and over again throughout the lifetime of the project to ensure that the classes and methods you worked so hard to write continue to work as designed even as other aspects of the project are added or modified? Too often we as a team, write something, test it, and later someone else is directed to make some other change, that causes previously coded features to un-expectantly fail. This is when unit testing comes in.

Instead of manually testing each component, visually inspecting the results, we can use a testing framework to exercise the code and evaluate if it still works or not. This works because we simply write a test that emulates the manual test that would have been written. For example, if you had written a math class and needed to test the add method, you could call that method passing 2 and 3 outputting the results. If it returned 5 it would seem reasonable to say that the add method works. Instead you could create a small test method that would also call the add method it would look something like this:

public void TestAdd()
{
Assert.AreEqual(5,MyMathClass.Add(2,3));
}

This method says the your add method should return 5 if it is passed 2 and 3 if it does not the test would be reported as a failure. Now that the test is save for all to re-run at any time. As each developer writes more components, they contribute more tests, which all would be run over and over again.

There are many excuses not to test
Though I think few would even attempt to argue that testing in general is not needed, most times much of it is left to the end of the project or even skipped completely. In-fact many times it is even regarded as a nuisance, causing more work than it is worth. I have heard countless excuses why testing is considered a second class citizen. My favorite is that we are too busy and simply don’t have time to do any more than minimal testing. I personally, am shocked every time I hear these words spoken. Consider for a moment how much time has been spent debugging code that was believed to be stable, just to find out later that it is not. How much time has been spent trying to track down bugs reported by users that cannot be easily replicated? In the end the cost of the test at the end strategy is far more than implementing a pay as you go approach.

One analogy I recently read said that it is far easier to mow the yard each week, then to try and cut a virtual forest once a week. Think about this for a moment, if more attention was paid to testing as the application was developed, many of the bugs would have been found and fixed before the system became too complex and too many other components were build atop the flawed logic.

Coding with Confidence
Invariably, by the time each project is enters the maintained phase, the team has already begun to distrusts the code base, and many already look forward to the day it is retired. As features are changed, developers do the absolute minimum to meet the new requirements. This means a lot of legacy code is left in the project for no other reason than the team member is terrified that removing or refactoring anymore than is absolutely necessary will lead to cascade failures across the system. This is where unit testing frameworks are so powerful. Tests that had been previously written can be run at anytime, ensuring each atomic element continues to perform as designed. This allows developers to code with confidence, instead of coping with the paralysis that so often causes us to do only the bare minimum.

The next step
So where do we start? Now that we hopefully agree in principal that unit testing is a good thing, we need a road map to implementation. The first step is to adapt a testing framework from which we can build all of our tests.

There are quite a few frameworks available the leaders in the .Net community include Microsoft Test, MBUnit, and NUnit among others.

Microsoft’s product though it does offer integration with Visual Studio. It first became available in Visual Studio 2005 Team Foundation, and limited support in now available in Visual Studio 2008 professional, but there are many features that remain unavailable to us. Additionally, this product has generally been regarded as an immature product by many prominent members of the .Net Community.

That leaves MBUnit and NUnit both are variations of the popular XUnit family of testing suites derived from Java’s JUnit.

MBUnit is the newer of the two frameworks; it actually builds upon NUnit, and has some interesting new features. Unfortunately, it is not nearly as widely used as NUnit and has far less available documentation available. It is for that reason I have chosen to us NUnit. It has been around for over 10 years, and the amount of information and support for this product is virtually endless. The only thing that remains is to get started with our first test…

(NUnit has an addin called TestDriven.Net which allows for tighter Visual Studio integration)
NUnit is probably the most mature unit testing framework of the bunch. It also has the biggest adoption and community support. There are more articles, discussions, tools and add ons for NUnit than any of the other frameworks combined. Just look at this link on google trends that compares searches for each of the frameworks. No other even comes close.