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()
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.).
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.
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.
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.
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(); } }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With