Mathias Brandewinder on .NET, F#, VSTO and Excel development, and quantitative analysis / machine learning.
by Mathias 10. May 2009 23:24

Compared to the recent releases, NUnit 2.5 contains quite a few significant changes. One notable change is in the area of exception testing – and it is for the better.

Until NUnit 2.4.8, testing for exceptions was done by decorating tests with the [ExpectedException] attribute. NUnit 2.5 introduces a new assertion instead, Assert.Throws.

Why is this better?

I see at least 2 reasons: it makes it much easier to catch the exception precisely where it is expected to happen, and working with the exception itself is now a breeze.

While the ExpectedException attribute is typically sufficient, it is a bit of a blunt tool. What it does verify is that the code under test throws the expected type of exception; what it  doesn’t tell you is where. The tests are not fully explicit, and sometimes, they can result in unexpected “false positives”.

Consider the following situation: a class MyClass exposes a method that takes a positive int as argument, and throws an ArgumentException if a negative is passed. A test for this behavior would look something like this:

[Test]
[ExpectedException(typeof(ArgumentException))]
public void FalsePositive()
{
    MyClass myClass = new MyClass();
    // This call is test setup, but will
    // throw an unwanted ArgumentException.
    myClass.SomeMethodThatThrows();
    // We want to check that this call throws.
    myClass.SomeMethodThatRequiresAPositiveArgument(-5);
}

Unfortunately, our setup contains a call to another method, which due to an error in our code, will throw an ArgumentException, too. The right type of exception is thrown, but absolutely not where we intend it – and the test will pass. Not good.

Granted, the example is pretty contrived, but situations like these do happen. To avoid this, you need to catch the exception “red handed”, exactly where it is supposed to take place – which requires cumbersome code code like this:

[Test]
[ExpectedException(typeof(ArgumentException))]
public void PainfulCorrectTest()
{
    MyClass myClass = new MyClass();
    try
    {
        // if the setup throws the test fails.
        myClass.SomeMethodThatThrows();
    }
    catch
    {
        Assert.Fail();
    }
    // We expect an exception in that portion of the code.
    myClass.SomeMethodThatRequiresAPositiveArgument(-5);
}

By wrapping the setup in a try/catch block, you can ensure that any exception that happens there will result in a failure of the test; the only “tolerated” exception has to occur after that block.

With NUnit 2.5, this problem disappears. The [ExpectedException] attribute is gone, and replaced by an assertion that verifies if a specific method call throws an exception:

[Test]
public void DelegateBasedTest()
{
    MyClass myClass = new MyClass();
    // We don't need to do anything about the setup.
    myClass.SomeMethodThatThrows();
    // The exception is expected here.
    Assert.Throws<ArgumentException>(
        delegate { myClass.SomeMethodThatRequiresAPositiveArgument(-5); });
}

This is really nice: the test pinpoints what exception is expected, AND exactly where it is supposed to happen. And with the “special” [ExpectedException] attribute gone, the syntax is more consistent.

The cherry on the cake is that Assert.Throws returns the actual exception that is thrown; it is totally straightforward to validate the state of the exception itself:

[Test]
public void RetrieveException()
{
    MyClass myClass = new MyClass();
    ArgumentException exception = Assert.Throws<ArgumentException>(delegate { myClass.SomeMethodThatRequiresAPositiveArgument(-5); });
    Assert.AreEqual("The Message.", exception.Message);
}

I really like this change in NUnit 2.5. The syntax does look a bit more intimidating, but the tests gain in clarity – which is crucial in a test suite. Tests are your best specification, and anything which reduces ambiguity there is a good thing!

Comments

8/2/2010 5:21:38 PM #

Harinath

Excellent job Mathias........
nicely explained, this helped me in creating Test cases for my project

Can you please give some examples on catching different exception types...


Regards,
Harinath Reddy

Harinath India | Reply

8/3/2010 11:15:47 AM #

mathias

Hi Harinath,
Thank you for the feedback! Specifying what type of exception is pretty straightforward. In my example, Assert.Throws<ArgumentException> specifies that an exception of type ArgumentException is expected. If another type of Exception was thrown, the test would fail, because while an exception is thrown, it is of the wrong type. Hope this helps!
Mathias

mathias United States | Reply

1/19/2011 4:16:02 PM #

JC

I like using lambdas here so you don't have to wrap the statement in braces or include the semicolon:

Assert.Throws<ArgumentException>(() => myClass.SomeMethodThatRequiresAPositiveArgument(-5));

JC United States | Reply

1/22/2011 5:20:44 AM #

mathias

JC,
Good remark. Today, now that I am comfortable with lambdas, this is also what I would do Smile

mathias United States | Reply

2/27/2012 6:43:26 AM #

Vishnu

Thank You,
   You're a life saver Smile

Vishnu India | Reply

6/27/2012 12:59:08 PM #

pingback

Pingback from starfootballlive.newpatriotmedia.com

D Eleinne Basa – Lines and Colors | Star Football Live

starfootballlive.newpatriotmedia.com | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Comments

Comment RSS