NUnit...

NUnit is an indispensable tool for automatically testing .NET applications. It's a tool for test-driven development in .NET.


By: Melwyn D'Souza and Sarvesh Damle Date: June 8, 2004 Download the code.

NUnit is an indispensable tool for automatically testing .Net applications. It's a tool for test-driven development in .NET. The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect. Each unit is tested separately before integrating them into modules to test the interfaces between modules. Unit testing has proven its value in that a large percentage of defects are identified during its use.

Use of NUnit?

NUnit does become a problem if you are trying to test your ASP.NET code. Not the middle-tier logic you tie into, but the .aspx pages themselves. How can you test that the UI reacts to the user correctly? That the postback events happen in the right order? That the correct next page is loaded after the user completes the page? Testing these things requires that your code is running inside the ASP.NET worker process. Your pages need access to the HTTPContext, the Request and Response objects, everything else that ASP.NET provides them at runtime. If you attempt to test your compiled .aspx pages directly from the NUnit test runner, none of them will even load, let alone pass your tests.

NUnit has quickly become a general practice (standard) among the product team where more developers, PM and testers have been pushing for this alternative. NUnit attributes can be extended by writing custom attributes by developers and testers.

The advantages of using NUnit in normal testing scenarios are:
- With minimum code, testers can acquire coverage on applications with an instrumentation tool.
- A suite of NUnit unit tests can set the minimum requirement for a code's minimum functional screening; therefore, this ensures that tester will not spend time on a broken build.

NUnitASP - The Solution

The typical attributes of the NUnit application are as follows:
NUnit uses attributes to mark the test code. Test code consists of:

The typical flow of writing of Unit test case is as follows:-

Step 1. Create a Class

Step 2. Add SetUp and TearDown

Step 3. Add a Test Case

Step 4. Use Assertion to test conditions

Test for Expected Errors

You could write up a bunch of mock objects to convince your pages that they are really running in ASP.NET. However, that list would include:

You would spend much more time writing this mock framework than writing any unit tests for your own application. NUnitASP, an open-source (MIT license) application, provides this framework for you. Or, more to the point, it let's your pages run in the actual ASP.NET worker process, but allows you to create a mock fa�ade container to test the UI with. This fa�ade creates all the server-side web- and html-control objects present on your page, whose properties you can manipulate and whose events you can fire. Then, you can check the results (of a postback or cross-page navigation).

To allow for this testing, NUnitASP has to provide not only a mock container for your pages but a browser imitation object that acts as the requesting client. The browser imitation object is what allows you to test the current URL, the cookies collection, and the static HTML output of a request. The collection of mock server controls allows you to manipulate and test the server-side properties and behavior of your pages.

The code being tested is loaded into its own application domain. Thus, the NUnit tool can load and reload the .NET assemblies you are testing without restarting the NUnit tool. In NUnit version 2.0 it looks for changes to the test assemblies and will reload them automatically to ensure that the latest binary assembly is being tested. This means you can perform code and test development cycles, running NUnit with loaded assemblies to be tested after each compilation without restarting and loading test fixtures.

The benefit of NUnit is that it integrates easily into unit testing and .NET in general, and is an excellent tool for system and regression testing. With the simple pass-fail user interface, there is no mistaking tests that failed and tests that passed. Because tests are written in .NET, analysts, programmers, and testers can codify tests and capture them as simple .NET algorithms that can be ascertained to validate the business rules.

How to implement a Test?

You need to download the NUnitASP ( http://nunitasp.sourceforge.net/download.html ).

To start using it, create a new ASP.NET Web Application project and add references to nunit.framework.dll (in the NUnit install's bin folder) and nunitasp.dll (in the NUnitASP install's bin folder).

NUnit provides a common tool for testing. Analysts can write both positive and negative test cases, which can be captured and codified in .NET by programmers who did not write the code, and the code either passes or fails. A second huge benefit is that the authors of the code can run the same tests during unit testing, getting a head start on bug-free code. Now your testers get started writing tests about the same time your coders do.

To demonstrate how all of this can and will work, include a trivial Windows Forms application, a class library representing business rules, and a test assembly that uses NUnit.

Building Sample Business Rules

Test code needs to be in a .DLL assembly, which is representative of the middleware part of your code commonly referred to as business rules. Because our emphasis is on testing, we can use just about any code, so I created a Class Library project containing a class named Numerics. Numerics perform simple verbose addition for integer and double numeric types (see Listing 1).

To create a negative test, I wanted to check overflow errors�when an arithmetic operation causes a number to exceed its maximum value, for example, 3,000,000,000 assigned to an integer contains more than 32 bits. To test an arithmetic overflow, I turned "Check for Arithmetic Overflow/Underflow" on in the Property Pages Configuration Properties Build (see Figure 1).


Figure 1 Enabling checks for arithmetic underflow and overflow.

Listing 1: Sample business rules we will be testing with NUnit.

using System;
namespace MyNumber
{
  public class Numerics
  {
    public static int AddTwoIntegers (int a, int b)
    {
      return a + b;
    }
    public static double AddTwoDoubles (double a, double b)
    {
      return a + b;
    }
  }
}

The code contains two static addition methods.

Building a GUI Application

For our purposes, the GUI simply demonstrates how to use the Numeric class and represents our presentation layer. The form I created contained three Textbox controls, three labels, and a button. Enter two numbers in each of the first two Textboxes, click the button and the result are shown in the third Textbox. The My Number assembly is referenced by the Windows Forms application, and the Numeric is invoked in the following manner:

textBox3.Text = Numerics.AddTwoIntegers (Convert.ToInt32 (textBox1.Text),
Convert.ToInt32 (textBox2.Text));

Configuring NUnit

We now have some code to test. We will need to download and install NUnit and then build our test fixture. You can download NUnit from http://www.nunit.org and use all the default values for installation. This will install the source code and binaries in \\Program Files\NUnit V2.0 by default.

Implementing the Test Assembly

Writing the tests represents the new information for us, so we'll take our time here.

A test is implemented as a Class Library. The test library references your business rules code and invokes operations on that code, just as your presentation layer will be doing.

The way that NUnit works is to load the test .DLL into an AppDomain object, relying on attributes and Reflection to determine which code represents tests. What we must do is apply attributes that NUnit will be looking for and write the tests appropriately. Listing 2 contains some tests I wrote for the MyNumber.Numerics, followed by an explanation of each of the attributes and the way the tests were written.

Listing 2: Test fixture for MyNumber.Numerics.

1: using System;
2: using NUnit.Framework;
3: using MyNumber;
4:
5: namespace Test
6: {
7:  [TestFixture ()]
8: public class TestNumerics
9: {
10:
11:  //[SetUp ()]
12:  public void Init ()
13:  {
14:    // Initialization for each test method here!!!
15:  }
16:
17:  [Teardown ()]
18:  public void Deinit ()
19:  {
20:    // De-initialization for each test method here!!
21:  }
22:
23:  [Test ()]
24:  public void AddTwoNumberPass ()
25:  {
26:    Assertion.AssertEquals ("Integer arithmetic passed",
27:    true, Numerics. AddTwoIntegers (10, 5) == 15);
28:  }
29:
30:  [Test ()]
31:  public void AddTwoDoublesPass ()
32:  {
33:    Assertion.AssertEquals ("Floating-point arithmetic passed",
34:    true, Numerics. AddTwoDoubles (1.3, 2.5) == 3.8);
35:  }
36:
37:  [Test (), ExpectedException (typeof (OverflowException))]
38:  public void AddIntegerFailed()
39:  {
40:    int a = 2147483647;
41:    int b = 5;
42:    Assertion.AssertEquals ("Integer overflow expected",
43:    true, Numerics. AddTwoIntegers ((int) a, (int) b) > 2147483647);
44:  }
45: }
46: }

NUnit attributes and classes that we will be defining are contained in \\Program Files\NUnit V2.0\bin\NUnit.Framework.dll. We will need to add a reference to NUnit.Framework.dll and MyNumber.dll�the code we will be testing. For convenience, I added a using clause to their respective namespaces as well.

To indicate that a class is a test fixture, apply the TestFixtureAttribute to the class, as shown on line 7.

If you need initialization and deinitialization code, add two methods to the test fixture. I named these Init and Deinit, but they can be anything. It is the SetUp Attribute�case-sensitive�and TearDown Attribute that points NUnit at these two methods. It is important to note that each of these methods will be called once before every method attributed with TestAttribute is called.

Next, we need some tests. Tests are adorned with the Test Attribute. Each test is a method that takes no arguments and returns void. Reflection is used to invoke these methods. Technically, return values and parameters can be invoked using Reflection; they would have to be contrived by NUnit because NUnit is running the test. However, it isn't the test method you are testing; it is the code in the test method. Because you write the test code, you can supply the arguments. I defined two positive tests AddTwoNumberPass and AddTwoDoublesPass, on lines 23 through 28, and on lines 31 through 35, respectively. Each of these tests uses the assertion class defined by NUnit. I invoked Assertion.AssertEquals on each of lines 26 and 33. The first argument is a message; the second argument is the value returned by the third argument. For example, line 27 evaluates an Add equal to 15. This should return true. We could also have used 15 as the second argument and the Arithmetic.Add method as the third, rewriting the lines 26 and 27 as Assertion.AssertEquals(message, 15, Arithmetic.Add(10, 5)).

Lines 27 through 44 incorporate a second attribute: ExpectedException Attribute. Passing the type record of an exception class, you can test to ensure that a test throws an expected exception. In the example, I intentionally create an overflow condition and want to ensure an exception is thrown.

Running Tests

Running the tests couldn't be easier. Run the NUnit GUI (or console version) and open the assembly containing the test fixture. Click the Run button. Tests that return Green passed, and Red indicates failed test (see Figure 2).After you change your code, simply return to NUnit and run the tests again.


Figure 2 Green indicates a passed test, and red indicates a failed test.

The console version of NUnit can be managed with a .cmd or .bat file, running tests at some scheduled time such as overnight or as part of a build process.

Where to Next

For more information on the full NUnitASP programming model, you can check out their API documents at http://nunitasp.sourceforge.net/api.html. The model contains other mock server controls, including ones for grids and tables which allow you to access their contents as arrays of objects. (Not all the WebControls have had mock controls implemented for them yet. The product is still in development.)

You may download the code here.