I'm looking for a way to catch exceptions globally in my NUnit project class library. So if one of my unit tests throws an exception, I can catch it in one spot. I don't want to surround each of my tests with a try/catch block. The reason I'm doing this is to print a nice error message with an explanation of the stack trace. In ASP.NET they have a method called Application_Error in Global.asax that does this sort of thing.
2 Answers
- You can create an Even listener: EventListeners (NUnit 2.4.4)
Interface
The extension object passed to Install must implement the EventListener interface:
public interface EventListener
{
void RunStarted( string name, int testCount );
void RunFinished( TestResult result );
void RunFinished( Exception exception );
void TestStarted(TestName testName);
void TestFinished(TestResult result);
void SuiteStarted(TestName testName);
void SuiteFinished(TestResult result);
void UnhandledException( Exception exception );
void TestOutput(TestOutput testOutput);
}
- You can make the try/catch block less ugly using the delegates (lambda expression) and closures.
Here is how it works:
public void Try(Action testCode)
{
try
{
testCode();
}
catch (Exception e)
{
Console.WriteLine("Nice Error Here: " + e.Message);
}
}
[Test]
public void TestO1()
{
int actual = 5;
int expected = 4;
Assert.AreEqual(expected, actual);
}
[Test]
public void TestO2()
{
int actual = 5;
int expected = 4;
Try( () => Assert.AreEqual(expected, actual) );
}
The method Try accepts the code as a parameter and executes it in the try block. So, in the catch block you can apply any necessary formatting.
The method TestO1 is just a usual unit test without any tricks.
The TestO2 has the assertion wrapped with the method Try:
Try( () => any line of code here );
It will be the same try/catch, but now I don’t need to write a lot of ugly code.
The EventListener
is the way to go. However there is a knack: the UnhandledException
will not be fired when an Assertion in your test fails. Rather use the TestFinished
event to handle failed tests:
public void TestFinished(TestResult result)
{
if (result.Executed && result.IsFailure)
{
Console.WriteLine(string.Format("Failure in test {0}", result.Name));
Console.WriteLine(result.Message);
}
}