Reduce runtime errors in .NET through unit testing
Takeaway: Does testing code rank low on your favorite things to do list? If so, check out Tony Patton's demonstration of how simple it is to effectively unit test your code using NUnit, a unit-testing framework for all .NET languages.
Microsoft's submission of the C# language and the CLR (Common Language Runtime) as industry standards has led to many open source projects based on the .NET platform. One such notable project is NUnit, a unit-testing framework for all .NET languages. I'll demonstrate the simplicity of using NUnit to effectively unit test your code.
Unit testing
Even though you may love developing code, you may not find thoroughly testing the code very appealing. It ranks right behind documentation. However, it's much more cost-effective for a developer to catch and fix problems during code development than waiting for someone in QA to find the problem, which would require the developer to revisit the code. This is the idea behind unit testing.
Unit testing involves testing the public interfaces of your application classes. That is, you test the classes to verify they perform as expected. This encompasses verifying that results are returned as expected, as well as proper exception handling. NUnit is an excellent tool to aid with these tasks. NUnit is a flexible testing framework for the .NET platform. It provides an easy-to-use interface for running your test.
NUnit is freely available from the NUnit.org Web site for both the Windows and Mono environments. (I'm using a Windows XP machine for this article, but the examples have been tested with Mono on SUSE 9.2 Linux distribution.) Let's take a closer look at the NUnit framework in action.
Working with NUnit
The NUnit architecture is straightforward. You can be up and running with sample tests in minutes as opposed to hours. Once you install it on a system, the framework is located in the nunit.framework.dll file. This file should be made available to your project to develop NUnit-based code. A reference may be added via Visual Studio .NET, or you can place it in the bin directory of your application. Next, you must add a reference to the NUnit namespace to your code (or utilize the complete path to NUnit classes). The following C# snippet demonstrates this:
using NUnit.Framework;
Here's the VB.NET equivalent:
Imports NUnit.Framework
Now you can use the classes in the NUnit.Framework namespace. But let's examine the many NUnit attributes before diving into code.
NUnit attributes
The NUnit framework utilizes custom attributes to specify NUnit elements utilized in code. These attributes are placed before the appropriate code elements. Here is a list of these attributes:
NUnit executes Setup first, then individual tests (it executes in the order it's listed in code if it isn't specified otherwise like running manually), and the TearDown section runs last. NUnit doesn't execute any code marked Ignore. In addition, NUnit provides numerous assertions to be used for unit testing (you may also develop custom methods), which are available via these methods of the Assert class:
You use these assertions to unit test your code. The best way to demonstrate it is via a code sample. The following C# class will be tested using NUnit:
using System;
using NUnit.Framework;
namespace UnitTestingSampleClass {
public class ExampleClass {
public string ConvertToUpper(string val)
{
return val.ToUpper();
}
public string ConvertToLower(string val) {
return val.ToLower();
} } }
This is a very simple class that provides two methods. The first method converts a string to uppercase, and the second method does the reverse by converting to lowercase. You have your class, but you still need to develop a corresponding NUnit class to test it. The NUnit class follows:
using System;
using NUnit.Framework;
using UnitTestingSampleClass;
namespace UnitTestingSample {
[TestFixture]
public class TestClass {
private string test1 = null;
private string test2 = null;
ExampleClass testObj = null;
[SetUp]
public void init() {
testObj = new ExampleClass();
test1 = "techrepublic.com";
test2 = TECHREPUBLIC.COM";
}
[Test]
public void TestA() {
Assert.AreEqual(testObj.ConvertToLower(test2),
test2.ToLower());
}
[Test]
public void TestB() {
Assert.AreEqual(testObj.ConvertToUpper(test1),
test1.ToUpper());
}
[Test]
[ExpectedException(typeof(NullReferenceException))]
public void NullTest() {
Assert.AreEqual(testObj.ConvertToLower(null),"");
}
[Test]
[Ignore("Not Used")]
public void TestC() { }
[Test]
public void TestD() {
Assert.AreEqual(testObj.ConvertToLower(test1),
test1.ToUpper());
}
[TearDown]
public void End() {
test1 = null;
test2 = null;
testObj = null;
} } }
This class contains five tests:
In addition, the init method runs before the tests (Setup) and the end (TearDown) method is called for cleanup once the tests have completed. NUnit includes a graphical interface for running the tests. You could test your sample with the following command line to call the interface and run the tests:
nunit-gui "c:\UnitTestingSample.exe" /run
The assembly was located in the root of the C drive on my system, so the path may be different on your system. You should specify the complete path to the assembly in the first parameter passed to nunit-gui. If you'd rather stick to the command line, you can use the command-line version with the following line:
nunit-console "c:\UnitTestingSample.exe"
This produced the following output on my system:
NUnit version 2.2.0
Copyright (C) 2002-2003 James W. Newkirk, Michael C. Two, Alexei
A. Vorontsov,
Charlie Poole..
Copyright (C) 2000-2003 Philip Craig.
All Rights Reserved.
OS Version: Microsoft Windows NT 5.1.2600.0 .NET
Version: 1.1.4322.573
....N.F
Tests run: 4, Failures: 1, Not run: 1, Time: 0.1093876
Failures:
1) TestUnitTestingConsole.TestClass.TestD :
String lengths are both 11.
Strings differ at index 0.
expected:<"techrepublic.com">
but was:<"TECHREPUBLIC.COM">
-----------^
at TestUnitTestingConsole.TestClass.TestD() in
c:\TestClass.cs:line 55
Tests not run:
1) TestUnitTestingConsole.TestClass.TestC : Not Used
Each approach provides numerous command-line options that you may view by using the /help command-line switch. The equivalent VB.NET code follows with the class to be tested listed first:
Public Class VBNetTestClass
Public Function ConvertToUpper(ByVal val As String) As
String
Return val.ToUpper()
End Function
Public Function ConvertToLower(ByVal val As String) As
String
Return val.ToLower()
End Function
End Class
This is the actual NUnit class for testing:
Imports NUnit.Framework
Imports UnitTestClassVBNet
<TestFixture()> Public Class Class1
Private test1 As String
Private test2 As String
Private testObj As VBNetTestClass
<SetUp()> Public Sub Init()
testObj = New VBNetTestClass
test1 = "techrepublic.com"
test2 = "TECHREPUBLIC.COM"
End Sub
<Test()> Public Sub TestA()
Assert.AreEqual(testObj.ConvertToLower(test2),
test2.ToLower())
End Sub
<Test()> Public Sub TestB()
Assert.AreEqual(testObj.ConvertToUpper(test1),
test1.ToUpper())
End Sub
<Test(), Ignore("sample ignore")> Public Sub TestC()
End Sub
<Test()> Public Sub TestD()
Assert.AreEqual(testObj.ConvertToLower(test1),
test1.ToUpper())
End Sub
<Test(), ExpectedException(GetType(NullReferenceException))>
Public Sub NullTest()
Assert.AreEqual(testObj.ConvertToLower(Nothing), "")
End Sub
<TearDown()> Public Sub CleanUp()
test1 = Nothing
test2 = Nothing
testObj = Nothing
End Sub
End Class
The sooner you catch runtime errors the better
Unit testing allows you to catch runtime errors much sooner than if you had to wait for a QA tester. In addition, it allows you to fix errors while the code is fresh in your memory. The process of creating tests before the actual code is gaining acceptance as well, but that's a topic for another time.
TechRepublic's free .NET newsletter, delivered each Wednesday, contains useful tips and coding examples on topics such as Web services, ASP.NET, ADO.NET, and Visual Studio .NET. Automatically sign up today!
Print/View all Posts Comments on this article
SponsoredWhite Papers, Webcasts, and Downloads
- Live Webcast: Save Time, Money and Manpower While Eliminating Redundancies from Your Data Backups PC Connection
- Demo: Need Disk Space? IBM DB2 9 Compression Demo IBM
- IBM Balanced Warehouse - The Flexible Foundation for Real Time Business Intelligence IBM
- Next Generation Mobility Now Sprint
- Case Study: Clackamas County Oregon's Outdated Fibre Channel Infrastructure Runs Out of Capacity Dell EqualLogic
Article Categories
- Security
- Security Solutions, IT Locksmith
- Networking and Communications
- E-mail Administration NetNote, Cisco Routers and Switches
- CIO and IT Management
- Project Management, CIO Issues, Strategies that Scale
- Desktops, Laptops & OS
- Windows 2000 Professional, Microsoft Word, Microsoft Excel, Microsoft Access, Windows XP,
- Data Management
- Oracle, SQL Server
- Servers
- Windows NT, Linux NetNote, Windows Server 2003
- Career Development
- Geek Trivia
- Software/Web Development
- Web Development Zone, Visual Basic, .NET





