Testing Visual Basic .NET with NUnit
Downloading and Installing NUnit
LNUnit V2.0 is available as an open source product from www.nunit.org. It is a framework implemented entirely in .NET for .NET languages. You can download the binaries and source for free and modify them—if you need to—as long as you adhere to the rules proscribed by nunit.org.
When you download NUnit you can select all of the default configuration options, which will place NUnit in the C:\Program Files\NUnit V2.0\ folder. For our purposes we will assume that NUnit is in the default location; however, you can install it anywhere.
After you have installed NUnit on your workstation you will see an NUnit shortcut on your desktop. This shortcut is for the GUI version. NUnit also ships a console version. We will use the GUI version here, but the console version might be ideal for an automated build, test, deploy cycle.
Building a Test Fixture
The basic process for defining a test is to create a class library, add a reference to the code you want to test to that library, define a class in the test class library, and adorn that class with the TestFixtureAttribute. TestFixtureAttribute is defined in the nunit.framework.dll assembly, so you'll need to add a reference to this assembly (found in C:\Program Files\NUnit V2.0\bin folder) and add an Imports statement to the .cs file containing your class library. After these steps NUnit will recognize your class library as one that will contain tests. The next step is to define those tests.
NUnit offers many tools for testing, but you can get started with a class adorned with the TestFixtureAttribute and just one method in that class adorned with the TestAttribute. Listing 1 offers a very simple class for the purposes of testing, and listing 2 shows you how easy it is to begin using NUnit. (Note: As a general practice you do not need to write your own sort. Any System.Array can be sorted by calling the Array.Sort shared method, which performs a quick sort. In addition, you can define an IComparer that will permit you to define custom comparisons for complex types. The sort method in listing 1 is simply there to demonstrate NUnit.)
Listing 1: Some code we want to test.
Public Class TestMePlease Public Shared Sub Swap(ByVal Values() As Integer, _ ByVal I As Integer, ByVal J As Integer) Dim Temp As Integer = Values(I) Values(I) = Values(J) Values(J) = Temp End Sub Public Shared Sub Sort(ByVal Values() As Integer) Dim I, J As Integer For I = Values.GetLowerBound(0) To Values.GetUpperBound(0) - 1 For J = I To Values.GetUpperBound(0) If (Values(I) > Values(J)) Then Swap(Values, I, J) End If Next Next End Sub Public Shared Sub Dump(ByVal Values() As Integer) Dim E As IEnumerator = Values.GetEnumerator While (E.MoveNext) Console.WriteLine(CType(E.Current, Integer)) End While Console.WriteLine("press enter") Console.ReadLine() End Sub End Class
Listing 1 contains a Bubble sort that plays the role of code we want to test. Here is listing 2 showing a simple test for the sort method.
Listing 2: An NUnit TestFixture that will test our code for us.
Imports NUnit.Framework Imports LibraryToTest <TestFixture()> _ Public Class Test <SetUp()> _ Public Sub Init() ' Initialization code here End Sub <TearDown()> _ Public Sub Deinit() ' De-initialization code here End Sub <Test()> _ Public Sub TestSortPass() Dim I() As Integer = {5, 4, 3, 2, 1} TestMePlease.Sort(I) Assertion.AssertEquals("Sort passed", 2, I(1)) End Sub End Class
Listing 2 contains a TestFixture. The class library containing the class in listing 2 is loaded into NUnit. NUnit uses Reflection to find classes adorned with the TestFixtureAttribute, create instances of that class, and execute methods adorned with special attributes. For example, at the start of each test methods with SetUpAttribute are run, followed by a single TestAttribute method, and finished with the method (if any) marked with the TearDownAttribute.
In our example in listing 2 Init, TestSortPass, and Deinit are run in that order. I don't have any initialization code; if you need to create an object for a specific test then the method marked with the SetUpAttribute is a good place to do it. Let's take a look at how we define tests now.
Defining Tests
Test methods—that is, methods that will be called directly by NUnit—are marked with the TestAttribute. Test methods are subroutines that have no parameters. Reflection can invoke methods with parameters and return types, but we are not testing the test method, we are testing the code inside the method. Thus, everything you need to perform a single test should occur inside the test method and the initialization method.
My test method is named TestSortPass. Adding a Pass or Fail suffix is a convention I follow. In TestSortPass I created an array of integers to pass to my sort method. I invoked the Sort method on the code that I am testing and then checked to see if an arbitrary value was in the correct position. The statement containing Assertion.AssertEquals is the code that comes from the NUnit framework.
There are eight overloaded versions of AssertEquals alone. The arguments in the overloaded version I used are a message, the result, and the test value. The statement is understood to mean that I(1) = 2, or that the second position in the array should have the second lowest value.When I load the class library containing the TestFixture into NUnit I will see a list of tests. You can click on a single test or the fixture and click Run to run those tests. Tests with a green circle succeeded and tests with a red circle failed (see figure 1).
Figure 1: The NUnit graphical user interface showing the test results for the TestSortPass test.
Advanced Teechniques
Even if all NUnit offered was a simple pass or fail test it would be worth using; however, the NUnit framework is quite extensive. You can use an IgnoreAttribute to mark tests that aren't quite ready. These tests won't run and will be so noted in NUnit with a yellow circle adjacent to the test. You can add an ExpectedExceptionAttribute and the type object of an exception to indicate that a test method should receive an exception and the type of the exception, and much more.
With a bit of cleverness you can devise useful tests for very complex applications. On a project I am working on we have even defined tests for ASP.NET. Exploring the source code, the online documentation, and experimentation will help you invent great ways to test your applications.
Page 2 of 3
This article was originally published on February 21, 2003