//Friday, 1 February 2008

Toolset (Part 4) - NUnit

NUnit is a unit-testing framework for .NET. You can download it here:

http://www.nunit.org/index.php?p=download

In this article I'm going to give a quick guide to how I set up my NUnit test projects. I'm not going to go into the reasons why test-driven development is a good idea, for that why not take a look at this:

http://www.codinghorror.com/blog/archives/000640.html (it has the added benefit of including a great picture of Mr T)

Creating your test project
Open the solution for your .NET application and add a new project of type Console Application. Call it XXXTests where XXX is the name of the application you are creating the tests for. Add references to the nunit assemblies nunit.core, nunit.core.interfaces and nunit.framework they will be located in the bin folder of your nunit installation (e.g. C:\Program Files\NUnit 2.4.3\bin\). Now add references to the web application you are testing and any shared assemblies that are required.

If your web application requires any configuration settings in order to run properly you will need to set these up in app.config, also in order to test via nunit.gui you will need to replicate this file and name it XXX.config where XXX is the name of your console application. So if for example your test project was called MyWebAppTests you will need to add a file to your project called MyWebAppTests.config that replicates app.config. For more information see (http://nunit.com/blogs/?p=9).

You should then create a test class for each class in your application. It should be named XXXTests where XXX is the name of the class. So to test a class called Data you would add a test class to your console application called DataTests.cs.

Build your project and then open up NUnit 2.4.3...NUnit Gui from your Start menu. Select File...New Project... navigate to the project directory for your test project and call the project file XXX.nunit where XXX is the name of your test project e.g. MyWebAppTests.nunit. Now go to Project...Add Assembly... and select the assembly for your test project e.g. MyWebAppTests.exe. All your tests should be listed with grey traffic lights select File...Save.

Now in Visual Studio click on your test project and select the Show All Files option. Your Nunit project file should be shown. Right click and select Include in Project. Right click again and select Open With... if it isn't already set it to be the Nunit Gui and set that to be the default (if it isn't in the list you might need to add it by browsing to C:\Program Files\NUnit 2.4.3\bin\nunit.exe. You will now be able to double click on the project file to launch the NUnit Gui.

Attributes
TestFixture
Each of the test classes will have this attribute at the top above the class declaration. This indicates to nunit that this class is to be included when the tests are run.

TestFixtureSetUp
Place this attribute above a method declaration to indicate that this method should be called before nunit starts running the tests in the class. This is useful for initializing objects/variables that you want to use throughout the tests e.g. reading a file, opening a database connection, etc.

TestFixtureTearDown
Place this attribute above a method declaration to indicate this method should be called after nunit has finished running the tests in the class. This is useful for finalizing any objects you created in the set up method e.g. closing a database connection.

Test
Place this attribute above a method declaration to indicate that this is a test. Each method that is marked with this attribute will appear in nunit-gui as a traffic light which will turn green or red depending on whether the test runs successfully.

ExpectedException
If you have tests which should always result in a particular exception you can use this attribute to detail what that exception is and what message you are expecting.

What to test
You should create at least one test for each method and property in each class. You should try and cover the complete functionality of your object so you should test success and failure. Try to think about all the possible ways in which the method or property could fail.

Example
Here is a simple example of a class and an associated test class.

Class to test:

using System;
using System.Collections.Generic;
using System.Text;

namespace MyClassLibrary
{
public class MyClass
{
#region Fields
private int _a;
private int _b;
private string _text;
#endregion

#region Constructors
public MyClass()
{
}
#endregion

#region Properties
public int A
{
get
{
return _a;
}
set
{
if (value <> 100)
{
throw new MyClassException("Value of A cannot be greater than 100");
}
_a = value;
}
}

public int B
{
get
{
return _b;
}
set
{
if (value > 0)
{
throw new MyClassException("Value of B cannot be more than zero");
}
if (value < -100) { throw new MyClassException("Value of B cannot be less than -100"); } _b = value; } } public string Text { get { return _text; } set { if (value != null && value.Length > 600)
{
throw new MyClassException("Length of text cannot be greater than 600");
}
_text = value;
}
}
#endregion

#region Methods
public int GetAPlusB()
{
return _a + _b;
}
#endregion
}
}


Test class:


using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using NUnit.Core;
using NUnit.Framework;
using MyClassLibrary;

namespace MyClassLibraryTests
{
[TestFixture]
public class MyClassTests
{
private StreamReader _validFile;
private StreamReader _tooLargeFile;

[TestFixtureSetUp()]
public void MyClassTests_SetUp()
{
// This is not best practice because ideally you wouldn't keep references to
// files open to avoid locking them however this is just to demonstrate
// the usage of the setup and teardown attributes
_validFile = new StreamReader(String.Format("{0}\\ValidFile.txt", Environment.CurrentDirectory));
_tooLargeFile = new StreamReader(String.Format("{0}\\TooLargeFile.txt", Environment.CurrentDirectory));
}

[TestFixtureTearDown()]
public void MyClassTests_TearDown()
{
_validFile.Close();
_tooLargeFile.Close();
}

[Test, ExpectedException(typeof(MyClassException), ExpectedMessage = "Value of A cannot be less than zero")]
public void A_Set_TooSmall()
{
MyClass obj = new MyClass();
obj.A = -10;
}

[Test, ExpectedException(typeof(MyClassException), ExpectedMessage = "Value of A cannot be greater than 100")]
public void A_Set_TooLarge()
{
MyClass obj = new MyClass();
obj.A = 101;
}

[Test, ExpectedException(typeof(MyClassException), ExpectedMessage = "Value of B cannot be less than -100")]
public void B_Set_TooSmall()
{
MyClass obj = new MyClass();
obj.B = -101;
}

[Test, ExpectedException(typeof(MyClassException), ExpectedMessage = "Value of B cannot be more than zero")]
public void B_Set_TooLarge()
{
MyClass obj = new MyClass();
obj.B = 1;
}

[Test]
public void GetAPlusB_CheckCalculation()
{
MyClass obj = new MyClass();
obj.A = 9;
obj.B = -3;
int result = obj.GetAPlusB();
Assert.AreEqual(6, result, String.Format("Expected result of GetAPlusB is 6 but actual value was {0}", result));
}

[Test]
public void Text_Set_Valid()
{
string validText = _validFile.ReadToEnd();
MyClass obj = new MyClass();
obj.Text = validText;
}

[Test, ExpectedException(typeof(MyClassException), ExpectedMessage = "Length of text cannot be greater than 600")]
public void Text_Set_TooLarge()
{
string tooLargeText = _tooLargeFile.ReadToEnd();
MyClass obj = new MyClass();
obj.Text = tooLargeText;
}
}
}
Debugging Your Tests
To debug your NUnit tests you can call your tests manually in the Main method of your console application and then run the application in debug mode as you would any other application. You will need to set your test application to be the startup project in your solution.


using System;
using System.Collections.Generic;
using System.Text;

namespace MyClassLibraryTests
{
class Program
{
static void Main (string[] args)
{
MyClassTestsDebug();
}

public static void MyClassTestsDebug()
{
// This allows me to debug a particular test method
MyClassTests myClassTests = new MyClassTests();
myClassTests.MyClassTests_SetUp();
try
{
myClassTests.Text_Set_TooLarge();
}
finally
{
myClassTests.MyClassTests_TearDown();
}
}

}
}
Alternative Method
If you would prefer to test through the Nunit Gui then right click on your test project in Visual Studio, select Properties and go to the Debug tab.

Change Start Action to be Start external program and set it to be NUnit Gui: C:\Program Files\NUnit 2.4.3\bin\nunit.exe.Set Command line arguments to be your Nunit test project e.g. MyWebAppTests.nunit.Set working directory to be the directory where the nunit project file is located (which should be the root of folder for your test project).Right click on the test project and select Set as Startup Project (if you haven't already).

Now when you click run in Visual Studio it will launch NUnit Gui when you run the tests in Nunit it will stop at any breakpoints you have set up in Visual Studio.

SyntaxHighlighter