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.