Unit Testing with Code Contracts

If your are not already using CodeContracts I really recommend to start using them now. And if you are already using them, you will have noticed that their exceptions cannot easily be caught. This is due to a design decision from the design team as stated in their Code Contracts User Manual:

7.6 ContractException

The ContractException type is not a public type and is emitted as a nested private type into each assembly for which runtime contract checking is enabled. It is thus not possible to write catch handlers catching only ContractException. Contract exceptions can thus only be handled as part of a general exception backstop. The rationale for this design is that programs should not contain control logic that depends on contract failures, just like programs should not catch ArgumentNullException or similar validation exceptions.

However, in some cases, especially when writing unit tests, it is helpful to provide a means to at least test these exceptions. When using the Microsoft Unit Testing Framework you can certainly decorate your test method with a generic ExpectedException(typeof(Exception) but this will not really tell you if a ContractException has really been thrown.

Sou to mitigate this shortcoming we can define our own attribute to decorate our test methods. This attribute is a standard attribute that derives from ExpectedExceptionBaseAttribute and checks for the exception name:

using System;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace biz.dfch.CS.Appclusive.Core.Tests
{
  public sealed class ExpectContractExceptionAttribute : ExpectedExceptionBaseAttribute
  {
    const string ContractExceptionName 
      = "System.Diagnostics.Contracts.__ContractsRuntime+ContractException";

    protected override void Verify(Exception exception)
    {
      if (exception.GetType().FullName != ContractExceptionName)
      {
        base.RethrowIfAssertException(exception);
        throw new Exception(
          string.Format(
            CultureInfo.InvariantCulture,
            "Test method {0}.{1} threw exception {2}, but contract exception was expected. Exception message: {3}",
            base.TestContext.FullyQualifiedTestClassName,
            base.TestContext.TestName,
            exception.GetType().FullName,
            exception.Message
          )
        );
      }
    }
  }
}

To utilise this attribute you only have to write your test method like this:

[TestMethod]
[ExpectContractException]
public void DividingByZeroThrowsContractException()
{
  double dividend = 4;
  double divisor = 0;

  var result = Divide(dividend, divisor);
}

private double Divide(double dividend, double divisor)
{
  Contract.Requires(0 != divisor);

  return dividend / divisor;
}

Trackbacks

  1. […] story … for more information also have a look about our other post about CodeContracts, the ExpectContractException attribute and Telerik […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: