Testing When Exceptions Are Expected
Been thinking about and looking at unit testing a lot recently. And, one of the items that came up was how do you test for expected exceptions to make sure that they're being thrown correctly. So, I wrote of few tests that did just that and noticed how similar they were, so I decided to create a helper method that exposed this test for easy use in all of my tests. These examples are all using the unit test framework that's part of VSTS, but the concept could be used for other C# based unit test tools.
The method uses an anonymous delegate to allow the caller to provide the code that should throw the exception, and wraps all the exception handling and test validation around it in the helper. The following is the code for the exception testing method:
namespace BlogLibraryTests
{
/// <summary>
/// Helper class that provides methods for helping unit test development, like handling
/// expected exceptions and serialization of classes.
/// </summary>
internal static class UnitTestHelper
{
#region Exception Handling Helpers
public delegate void ExceptionTestDelegate();
/// <summary>
/// Tests method for an expected exception being thrown.
/// </summary>
/// <param name="del"></param>
/// <param name="exception"></param>
static public void TestException(ExceptionTestDelegate del, Type exception)
{
try
{
// Call the delegate, fail the test if it doesn't throw an exception.
del();
Assert.Fail("Test should have thrown exception " + exception.ToString() + ".");
}
catch (AssertFailedException)
{
// If it's a failed assert, then just rethrow because it's our failure above.
throw;
}
catch (Exception e)
{
// Test that the method threw the exception that we were expecting.
Assert.IsInstanceOfType(e, exception, "Exception is not of the expected type.", exception.ToString());
}
}
#endregion
}
}
The code above will ensure that an exception was actually thrown, or fail otherwise. And, if there was an exception, that it's the type of exception that we were expecting. Not an overly complex amount of code, but very repetitive for every method that you're testing that throws an exception.
Then calling it is just a matter of providing a delegate with the code that should throw the exception and the expected exception type:
/// <summary>
///A test for NamedElement (string)
///</summary>
[TestMethod()]
public void ConstructorTest()
{
// Test with valid name string.
string expected = "Foo";
string name = expected;
NamedElement target = new NamedElement(name);
Assert.AreEqual(target.Name, expected, "NamedElement(name) didn't initialize correctly.");
// Test with null name string.
UnitTestHelper.TestException(delegate() { target = new NamedElement(null); }, typeof(ArgumentNullException));
}
As you can see it makes for compact test writing and makes it easy to create a bunch of tests that ensure that your code throws the appropriate exceptions.
Comments
Anonymous
September 24, 2007
PingBack from http://www.artofbam.com/wordpress/?p=2531Anonymous
September 24, 2007
But how is this really different than the ExpectedException attribute that can be applied to test methods in unit tests?Anonymous
September 24, 2007
Indeed doesn't seem to be much different since this is also only checking the type.Anonymous
September 27, 2007
The Teams WIT Tools Blog on Dashboard Creator - Part III. Mike Azocar on An Addendum... Ognjen Bajic...Anonymous
September 27, 2007
Yes indeed similar to ExpectedException, but you can also write more validation in this method if you want to... especially if you are defining a bunch of custom exceptions for your application.Anonymous
October 15, 2007
The comment has been removedAnonymous
October 15, 2007
The comment has been removedAnonymous
October 18, 2007
Yes, that's right, thanks Bernie. The attribute only really tells that an exception was thrown in that test method... Not that it was thrown by the code that you were expecting to throw it. And, I do like the generic part of it too.