Freigeben über


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=2531

  • Anonymous
    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 removed

  • Anonymous
    October 15, 2007
    The comment has been removed

  • Anonymous
    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.