We have some NUnit tests that access the database. When one of them fails it can leave database in inconsistent state - which is not an issue, since we rebuild database for
This idea got me interested, so I did a little digging. NUnit doesn't have this ability out of the box, but there is a whole extensibility framework supplied with NUnit. I found this great article about extending NUnit - it was a good starting point. After playing around with it, I came up with the following solution: a method decorated with a custom CleanupOnError
attribute will be called if one of the tests in the fixture failed.
Here's how the test looks like:
[TestFixture]
public class NUnitAddinTest
{
[CleanupOnError]
public static void CleanupOnError()
{
Console.WriteLine("There was an error, cleaning up...");
// perform cleanup logic
}
[Test]
public void Test1_this_test_passes()
{
Console.WriteLine("Hello from Test1");
}
[Test]
public void Test2_this_test_fails()
{
throw new Exception("Test2 failed");
}
[Test]
public void Test3_this_test_passes()
{
Console.WriteLine("Hello from Test3");
}
}
where the attribute is simply:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class CleanupOnErrorAttribute : Attribute
{
}
And here is how it's executed from the addin:
public void RunFinished(TestResult result)
{
if (result.IsFailure)
{
if (_CurrentFixture != null)
{
MethodInfo[] methods = Reflect.GetMethodsWithAttribute(_CurrentFixture.FixtureType,
CleanupAttributeFullName, false);
if (methods == null || methods.Length == 0)
{
return;
}
Reflect.InvokeMethod(methods[0], _CurrentFixture);
}
}
}
But here's the tricky part: the addin must be placed in the addins
directory next to the NUnit runner. Mine was placed next to the NUnit runner in TestDriven.NET directory:
C:\Program Files\TestDriven.NET 2.0\NUnit\addins
(I created the addins
directory, it wasn't there)
EDIT Another thing is that the cleanup method needs to be static
!
I hacked together a simple addin, you can download the source from my SkyDrive. You will have to add references to nunit.framework.dll
, nunit.core.dll
and nunit.core.interfaces.dll
in the appropriate places.
A few notes: The attribute class can be placed anywhere in your code. I didn't want to place it in the same assembly as the addin itself, because it references two Core
NUnit assemblies, so I placed it in a different assembly. Just remember to change the line in the CleanAddin.cs
, if you decide to put it anywhere else.
Hope that helps.