headerphoto

blogs > Development - Test-Driven Development (TDD) > Exception assertions

Created Monday, August 23, 2010 by simonwilbert

Last updated 532 days ago, by simonwilbert

If you're writing unit tests, and have been trying to test exceptions, then this is a must-read.

Scenario

If you've a method call that will cause an exception that your testing, you may have written the following… (Note: bob is single parameter on constructor)

      [Test, ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: bob")]
      public void ConstructionWithNull()
      {
         new MyObject(null);
      }

Issue

Code coverage will drop as the last parenthesis will never get hit by the unit test. Code coverage tools will conside the above method to have 2 lines of code, therefor you will only get 50% coverage!

Work-around 1

A work around is to drop the expectedexception attribute on the test method and use a try/catch when making the call, with 2 asserts in the catch (1) test correct exception type (2) test corrected exception message.

      [Test]
      public void ConstructionWithNull()
      {
         try
         {
            new MyObject(null);
         }
         catch(Exception ex)
         {
            Assert.That(ex.GetType(), Is.EqualTo(typeof(ArgumentNullException)));
            Assert.That(ex.Message, Is.EqualTo("Value cannot be null.\r\nParameter name: bob"));
         }
      }

This work-around requires you to add quite a few extra lines of code, making the test harder to read for the sake of improving code coverage.

Solution 1

The expected… attributes you can apply to test methods are nice, but if your able to state expected exceptions in attributes, why cant you state expected comparison values?

Its therefore better to state exception assertions as statements within the test, rather than as method attributes. This can be achieved using the "Assert.Throws" anonymous assertion method shown below.

      [Test]
      public void ConstructionWithNull()
      {
         Assert.Throws(
            delegate
            {
               new MyObject(null);
            }, "Value cannot be null.\r\nParameter name: bob");
      }

This is a good solution because:

  • All your test method consistant use assertion statements, rather than a mix of assertion statements and assertion method attributes.
  • Code coverage is 100% The test is readable and explicit in your assertions.

Final Solution (Lambda expression)

Solution 1 is nice, but could be made slightly more readable by using a lambda expression. If you've not heard of this, then it’s an anonymous method that can contain expressions and statements, and can be used to create delegates or expression tree types. Doing so will result in our final solution shown below.

      [Test]
      public void ConstructionWithNull()
      {
         Assert.Throws(
            () => new MyObject(null), 
            "Value cannot be null.\r\nParameter name: bob");
      }

This solution is good because:

  • All the reasons of Solution 1
  • More readable and explicit in what it does

I hope this helps when writing your unit tests!

Add comment | Back to blog

Comments (0)

Add comment