Scott Dorman

ephemeral segment

  Home  |   Contact  |   Syndication    |   Login
  603 Posts | 10 Stories | 862 Comments | 51 Trackbacks

News


Post Categories

Image Galleries


Microsoft Store


Creative Commons License



Locations of visitors to this page

Subscribers to this feed

TwitterCounter for @sdorman

View blog authority

Add to Technorati Favorites

Windows Live Alerts

AddThis Social Bookmark Button

LinkedIn profile

Community Credit profile

The Code Project

Follow me on Twitter

Get Free Shots from Snap.com

Community Credit Hall of Fame

Get Feedghost

Xobni outlook add-in for your inbox



Support This Site

Tag Cloud


Article Categories

Archives

Post Categories

Image Galleries

When writing unit tests that cover methods that can throw known exceptions, you generally want to make sure that your tests actually test the conditions that can cause the exception and that you do, in fact, throw the correct exception.

Most unit test frameworks, including MSTest and NUnit, use an ExpectedExceptionAttribute to decorate the test method. There are actually several problems with using ExpectedExceptions that make it more difficult to write good unit tests.

The first problem is the fact that once a test method with an ExpectedException attribute throws an exception the execution of that method stops. Why is that a problem? It’s a problem because now you must write a separate test for each exception you might throw. This in and of itself isn’t a problem but it does become very cumbersome and results in a lot of extra code.

The second problem is that the syntax is the same (or similar) but the behavior is different between different unit testing frameworks. For example, NUnit and MSTest both allow a message parameter on their ExpectedException attributes. However, in NUnit this is the expected message the exception contains while MSTest uses this as the message that will be reported if an exception is thrown that isn’t the correct type.

Finally, it doesn’t specify which line of code might actually throw the exception. It simply says that something in the unit test should throw an exception. Since the actual exception handling is done outside of the test, you don’t have the ability to inspect the details of the exception.

There are some unit testing frameworks, like xUnit.net that recognized these problems and took steps to address them. In xUnit.net, there are Assert.Throws, Assert.DoesNotThrow, and Record.Exception constructions. The Assert.Throws ensures that the code throws that exact exception while Assert.DoesNotThrow ensures the code does not throw any exceptions. Record.Exception simply records any exception that is thrown.

I wanted a way that worked like the xUnit.net Assert.Throws method and found a solution by Chris Marino. This solution only works on .NET 2.0 or later as it uses the System.Action delegate. He does talk about an interesting JIT related bug in his original implementation. I have found a work around for the JIT bug he mentions and have been successfully converting my unit tests to make use of this new style of expected exception testing.

I have taken his solution, worked around the JIT bug and also added a related method that allows you to verify the message of the exception as well:

   1: /// <summary>
   2: /// Contains assertion types that are not provided with the standard MSTest assertions.
   3: /// </summary>
   4: internal static class ExceptionAssert
   5: {
   6:     /// <summary>
   7:     /// Checks to make sure that the input delegate throws a exception of type TException.
   8:     /// </summary>
   9:     /// <typeparam name="TException">The type of exception expected.</typeparam>
  10:     /// <param name="blockToExecute">The block of code to execute to generate the exception.</param>
  11:     public static void Throws<TException>(Action blockToExecute) where TException : System.Exception
  12:     {
  13:         try
  14:         {
  15:             blockToExecute();
  16:         }
  17:         catch (Exception ex)
  18:         {
  19:             Assert.IsTrue(ex.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
  20:             return;
  21:         }
  22:  
  23:         Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
  24:     }
  25:  
  26:     /// <summary>
  27:     /// Checks to make sure that the input delegate throws a exception of type TException.
  28:     /// </summary>
  29:     /// <typeparam name="TException">The type of exception expected.</typeparam>
  30:     /// <param name="blockToExecute">The block of code to execute to generate the exception.</param>
  31:     public static void Throws<TException>(string expectedMessage, Action blockToExecute) where TException : System.Exception
  32:     {
  33:         try
  34:         {
  35:             blockToExecute();
  36:         }
  37:         catch (Exception ex)
  38:         {
  39:             Assert.IsTrue(ex.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead.");
  40:             Assert.AreEqual(expectedMessage, ex.Message, "Expected exception with a message of '" + expectedMessage + "' but exception with message of '" + ex.Message + "' was thrown instead.");
  41:             return;
  42:         }
  43:  
  44:         Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown.");
  45:     }
  46: }

This implementation should work with any unit testing framework.

DotNetKicks Image
posted on Saturday, January 17, 2009 1:20 PM

Feedback

# re: Unit Testing and Expected Exceptions 2/5/2009 5:37 PM mhenry1384
Thanks, this is perfect. Much better than the ExpectedException attribute.

# re: Unit Testing and Expected Exceptions 8/28/2009 5:08 AM johnny
Excellent post - I was just about to write something similar myself!

Thank you for sharing!!!

# re: Unit Testing and Expected Exceptions 3/23/2010 3:57 AM kazim mehdi
great post thanks

# re: Unit Testing and Expected Exceptions 8/16/2010 11:00 AM Josh
As much as this is helpful, I still get thrown off course by exceptions. Can you suggest any more?

# re: Unit Testing and Expected Exceptions 3/1/2011 4:51 PM Newbie
I have to admit I don't understand how to implement. I turned it into an attribute but that doesn't really seem to be the way you indicated. So this isn't a replacement to the ExpectedException decoration...? I use it inline with the assert? Just a one line example is all I need.
Thank you

# re: Unit Testing and Expected Exceptions 10/26/2011 6:26 AM Raj Aththanayake
In regards to The first problem ....

You said....
"The first problem is the fact that once a test method with an ExpectedException attribute throws an exception the execution of that method stops. Why is that a problem? It’s a problem because now you must write a separate test for each exception you might throw. This in and of itself isn’t a problem but it does become very cumbersome and results in a lot of extra code."

Hope I understood correctly - I agree that the execution get stopped for the thrown exception.However your first Unit Test would have had the necessary behaviour to throw the exception. Now you would use a different Unit Test to throw a different exception while ensuring that you would not throw an exception for the previous Unit Test.
It is always a good to write separate Unit Tests for separate exceptions. AKA Test isolation IMO.

Btw, I must say very nice implementation of Assert.Throws<T>
Thx for the post.


# re: Unit Testing and Expected Exceptions 11/25/2011 7:34 PM zak
Hi! -
Instead of using Assert.IsTrue why not use (simplified)
Assert.IsInstanceOfType(ex,typeof(TExpectation));

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: