Frictionless Testing with TestDriven.NET
Much has been written in the last several years about the benefits of unit testing and test-driven development. The basic idea is that you should write a test for every bit of functionality in your application, and exercise these tests as you go along to make sure that you didn't break anything. Proper use of these techniques can lead to increased confidence and fewer errors in your code. A number of tools, such as NUnit, MbUnit, and even (for those of you brave enough to run the Visual Studio 2005 beta) Microsoft Team System now support unit testing for .NET development. But a new entrant to the .NET ecosphere, TestDriven.NET, makes the process easier than ever. In this article, I'll show you how.
Writing and Running Your First Test
Other tools, such as NUnit, run as external applications. They test your code outside of the IDE. TestDriven.NET, in contrast, hooks unit testing directly up to Visual Studio .NET. It can also make use of any of the testing frameworks I've already mentioned; it comes with a bundled copy of MbUnit, so that's what I'll use here. To get started, download a copy of TestDriven.NET and install it. The download is free, although you do need to register with the site to get it. Then create a new Visual Basic .NET class library project using Visual Studio .NET 2003.
The simple project I'll develop will let callers determine some properties of numbers. I've added two classes to the project: Number.vb, which will contain the actual code for the class, and NumberTests.vb, which will contain test code. To see the mechanics of TestDriven.NET, I'll start with a simple implementation of Number. The first thing this class needs to do is to be able to set the value of the number and retrieve it. Here's a skeleton that defines the proper interface:
Public Class Number Public Sub New() End Sub Public Property Value() As Integer Get End Get Set(ByVal Value As Integer) End Set End Property End Class
You're probably looking at that code and thinking that there's no way that it could possibly work - and you're right. But one of the tenets of test-driven development is to write tests before you write code. That way you can be sure you know why you're writing each bit of code. So, let's move on to write a test.
Because I'm going to use MbUnit for the actual testing, I need to add references to MbUnit's two libraries: MbUnit.Core.dll and MbUnit.Framework.dll. These libraries get installed to the MbUnit folder beneath the TestDriven.NET install location. With the MbUnit objects available, it's time to write the start of the test class:
Imports System Imports MbUnit.Core.Framework Imports MbUnit.Framework
_ Public Class NumberTests _ Public Sub TestValue() ' Make sure we can store and retrieve a value Dim num As New Number num.Value = 5 Assert.AreEqual(num.Value, 5) End Sub End Class
MbUnit, like the other .NET unit-testing frameworks, uses attributes to carry
TestFixtureAttribute attribute indicates that this
class contains tests. The
Test attribute on the
TestValue method indicates that this method is a unit test. This
particular test instantiates a
Number object, sets its value, and
then tests the value using the MbUnit
Assert object. If the two
arguments to the
AreEqual method are the same, the test is a
success; otherwise, it's a failure.
Now it's time to see how easy it is to run a test using TestDriven.NET. Right-click in the test class and select Run Test(s). TestDriven.NET will compile the project, find the appropriate tests, run them, and display the results in the Visual Studio .NET output pane. In this case, the output ends with the ominous warning:
0 succeeded, 1 failed, 0 skipped, took 0.00 seconds
Yes, the test failed (which is hardly surprising, because the Value property is only partially implemented). Even better, MbUnit saves its output as an HTML file, and TestDriven.NET obligingly provides a link to this file in the output pane. Control-click the link to open the output report right in the IDE, as shown in Figure 1. As you can no doubt guess, the unhappy red colors indicate that not all is well here.