In this article, I show you a way to debug your NUnit test scripts. This trick lets you write test scripts only once and use them twice, for debugging and for unit testing.
Introduction
NUnit is cool. But if not properly used - it can be expensive. Some developers dislike it because they say it doubles their work. Typically, they will develop a short segment of code and step through it with the debugger. After it has been stabilized, they will write NUnit compliant test scripts. Hence, they will either write tests twice or migrate existing ones to NUnit - both actions will require additional effort!
In this article, I will show you a way to debug your NUnit test scripts. This trick will let you write test scripts only once and use them twice: for debugging and for unit testing.
Prerequisites
- NUnit 2.1 installed to default folder (C:\Program Files\NUnit V2.1)!
- Visual Studio.NET 2003
The Sample Project
To demonstrate the concept, we will need a small project consisting of two libraries. Each library will contain one function and its tests.
Figure 1. Solution
Here is the code for ClassA.cs and ClassB.cs. For now, ignore other files in the solution - I'll explain their meaning later.
using System;
namespace LibraryA
{
public class ClassA
{
public int Add(int a, int b) {return a+b;}
}
}
using System;
namespace LibraryB
{
public class ClassB
{
public int Mul(int a, int b) { return a*b; }
}
}
Tests
We will put the test code for each library inside the library itself. Some programmers prefer to put all tests to a separate project. This project then contains test code of the entire solution.
There is a downside to this. Imagine you want to reuse the library. If tests are inside the library, you can simply copy it to the new solution. If not, then you have to extract tests and copy them to the new solution.
#if (DEBUG)
using System;
using NUnit.Framework;
namespace LibraryA
{
[TestFixture]
public class LibraryATests
{
[Test]
public void Add()
{
ClassA classA=new ClassA();
Assertion.Assert(classA.Add(10,20)==30);
}
}
}
#endif
#if (DEBUG)
using System;
using NUnit.Framework;
namespace LibraryB
{
[TestFixture]
public class LibraryBTests
{
[Test]
public void Mul()
{
ClassB classB=new ClassB();
Assertion.Assert(classB.Mul(10,20)==200);
}
}
}
#endif
There are no standards for naming or structuring your tests. I prefer putting them all to one class. The name of this class is <LibraryName>Tests (i.e., LibraryATests
for tests for LibraryA
). Works good for me but de gustibus non est disputandum.
I also prefer not to distribute tests with release version of software thus I put #if (DEBUG)
directive around test fixtures.
Making NUnit Start When We Run the Solution
There are several ways to integrate testing & debugging:
- Run NUnit giving it the solution file as a command line parameter and then attach to the process. As soon as you are attached, you can set breakpoints.
- Rename NUnit-GUI.exe to NUnit-GUI.dll and initialize & run it from an executable. Markus Kalina described the procedure for this ugly hack in detail here.
- Create NUnit surrogate project in your solution and configure it so that NUnit is run every time you try to start it. I find this solution most practical and use it.
To create NUnit surrogate, we first need to create a test project. Test project is a special file with extension .nunit which lists all libraries that contain unit tests. Here are the contents of NUnitTests.nunit
test project file.
<NUnitProject>
<Settings activeconfig="Debug" />
<Config name="Debug">
<assembly path="LibraryA\bin\Debug\LibraryA.dll" />
<assembly path="LibraryB\bin\Debug\LibraryB.dll" />
</Config>
<Config name="Release"></Config>
</NUnitProject>
I commonly save this file to solution root folder and add it as solution item. This ensures that the source control systems store it together with the solution.
Next, we create a new console application and add it to the solution. We don't need to modify the code of this application since we'll only use this project as a surrogate to invoke NUnit GUI. If you do change the code, then make sure that it always contains the Main
function so that the compiler will not complain. Here is what you can use:
using System;
namespace NUnitTests
{
class DummyApp
{
[STAThread]
static void Main(string[] args)
{
}
}
}
Now configure VS.NET to start NUnit-GUI.exe taking NUnitTests.nunit
as command line parameter.
Do this by right clicking your console application in the Solution Explorer and selecting Properties. Then change settings: Debug Mode, Start Application, Command Line Arguments, and Always Use Internet Explorer as shown in the figure below. VS.NET is a bit buggy. You will have to first change setting Always Use Internet Explorer to True and Debug Mode to Program. Then you will have to press button Apply. Only then will you be able to edit other fields.
Figure 2. Settings to run Nunit-GUI.exe
After confirming new settings every time you try to run the surrogate application, you'll start NUnit GUI.
Figure 3. No bugz
Because NUnit GUI will be started by VS.NET, the debugger will attach to the process automatically. You'll be able to select and run tests of the solution (NUnit GUI will show all projects listed in NUnitTests.nunit file) and use the debugger as if you were running your console application instead.
VS.NET User Settings
For some reason, VS.NET stores project settings (Start Action and Start Application from Figure 2) to user settings file (with extension .user). Settings are stored to NUnitTests.csproj.user in the NunitTests project folder (NOT in the solution folder). Following is the subset of this file:
<VisualStudioProject>
<CSHARP LastOpenVersion="7.10.3077">
<Build>
<Settings ReferencePath="">
<Config Name="Debug" EnableASPDebugging="false"
EnableASPXDebugging="false" EnableUnmanagedDebugging="false"
EnableSQLServerDebugging="false"
RemoteDebugEnabled="false" RemoteDebugMachine=""
StartAction="Program"
StartArguments="..\..\..\NUnitTests.nunit"
StartPage=""
StartProgram="C:\Program Files\NUnit V2.1\bin\nunit-gui.exe"
StartURL="" StartWorkingDirectory="" StartWithIE="true" />
</Settings>
</Build>
</CSHARP>
</VisualStudioProject>
The problem is that user settings are not checked in to the Source Safe when you check in from VS.NET. Thus, next time you check out the entire solution (say, to another machine), your settings are lost and you have to reconfigure the project.
I have not found a good solution for this problem. At present, I manually check in and check out UnitTests.csproj.user. I only have to do it once per machine because subsequent check ins and check outs will not affect user settings file. Let me know if you find anything better.
History
- 25th February, 2004: Initial version
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.