Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NUnit - cleanup after test failure

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 every test run - but it can cause other tests to fail in the same run.

Is it possible to detect that one of the tests failed and perform some sort of cleanup?

We don't want to write cleanup code in every test, we already do that now. I'd like to perfrom cleanup in Teardown but only if test failed, as cleanup might be expensive.

Update: To clarify - I would like tests to be simple and NOT include any cleanup or error handling logic. I also don't want to perform database reset on every test run - only if test fails. And this code should probably be executed in Teardown method but I am not aware of any way to get info if test we are currently tearing down from failed or was successful.

Update2:

        [Test]         public void MyFailTest()         {             throw new InvalidOperationException();         }          [Test]         public void MySuccessTest()         {             Assert.That(true, Is.True);         }          [TearDown]         public void CleanUpOnError()         {             if (HasLastTestFailed()) CleanUpDatabase();         } 

I am looking for implementation of HasLastTestFailed()

like image 262
bh213 Avatar asked Jul 15 '09 14:07

bh213


People also ask

Which attribute can be used to do the clean up work once all the tests are done in NUnit?

Action Attributes are a feature of NUnit designed to better enable composability of test logic. Often when writing unit tests we have logic that we want to run upon certain events in the test cycle (e.g. SetUp, TearDown, FixtureSetUp, FixtureTearDown, etc.).

What is TearDown in NUnit?

This attribute is used inside a TestFixture to provide a common set of functions that are performed after each test method. TearDown methods may be either static or instance methods and you may define more than one of them in a fixture.

How do I skip a NUnit test case?

IgnoreAttribute (NUnit 2.0) The ignore attribute is an attribute to not run a test or test fixture for a period of time. The person marks either a Test or a TestFixture with the Ignore Attribute. The running program sees the attribute and does not run the test or tests.

What is TestFixture NUnit?

The [TestFixture] attribute denotes a class that contains unit tests. The [Test] attribute indicates a method is a test method. Save this file and execute dotnet test to build the tests and the class library and then run the tests. The NUnit test runner contains the program entry point to run your tests.


2 Answers

Since version 2.5.7, NUnit allows Teardown to detect if last test failed. A new TestContext class allows tests to access information about themselves including the TestStauts.

For more details, please refer to http://nunit.org/?p=releaseNotes&r=2.5.7

[TearDown] public void TearDown() {     if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)     {         PerformCleanUpFromTest();     } } 
like image 102
Ran Avatar answered Sep 26 '22 20:09

Ran


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.

like image 29
Igal Tabachnik Avatar answered Sep 25 '22 20:09

Igal Tabachnik