Exception Asserts (NUnit 2.5)

The Assert.Throws method is pretty much in a class by itself. Rather than comparing values, it attempts to invoke a code snippet, represented as a delegate, in order to verify that it throws a particular exception.

It's also in a class by itself in that it returns an Exception, rather than void, if the Assert is successful. See the example below for a few ways to use this.

Assert.Throws may be used with a constraint argument, which is applied to the actual exception thrown, or with the Type of exception expected. The Type format is available in both both a non-generic and (in the .NET 2.0 version) generic form.

Assert.DoesNotThrow simply verifies that the delegate does not throw an exception.

Assert.Catch is similar to Assert.Throws but will pass for an exception that is derived from the one specified.

Exception Assert.Throws( Type expectedExceptionType, TestDelegate code );
Exception Assert.Throws( Type expectedExceptionType, TestDelegate code, 
		string message );
Exception Assert.Throws( Type expectedExceptionType, TestDelegate code, 
		string message, params object[] parms);

Exception Assert.Throws( IResolveConstraint constraint, TestDelegate code );
Exception Assert.Throws( IResolveConstraint constraint, TestDelegate code, 
		string message );
Exception Assert.Throws( IResolveConstraint constraint, TestDelegate code, 
		string message, params object[] parms);

T Assert.Throws<T>( TestDelegate code );
T Assert.Throws<T>( TestDelegate code, string message );
T Assert.Throws<T>( TestDelegate code, string message, 
		params object[] parms);
		
void Assert.DoesNotThrow( TestDelegate code );
void Assert.DoesNotThrow( TestDelegate code, string message );
void Assert.DoesNotThrow( TestDelegate code, string message, 
        params object[] parms);

Exception Assert.Catch( TestDelegate code );
Exception Assert.Catch( TestDelegate code, string message );
Exception Assert.Catch( TestDelegate code, string message, 
        params object[] parms);

Exception Assert.Catch( Type expectedExceptionType, TestDelegate code );
Exception Assert.Catch( Type expectedExceptionType, TestDelegate code, 
		string message );
Exception Assert.Catch( Type expectedExceptionType, TestDelegate code, 
		string message, params object[] parms);

T Assert.Catch<T>( TestDelegate code );
T Assert.Catch<T>( TestDelegate code, string message );
T Assert.Catch<T>( TestDelegate code, string message, 
		params object[] parms);

In the above code TestDelegate is a delegate of the form void TestDelegate(), which is used to execute the code in question. Under .NET 2.0, this may be an anonymous delegate. If compiling under C# 3.0, it may be a lambda expression.

The following example shows different ways of writing the same test.

[TestFixture]
public class AssertThrowsTests
{
  [Test]
  public void Tests()
  {
    // .NET 1.x
    Assert.Throws( typeof(ArgumentException),
      new TestDelegate(MethodThatThrows) );
	  
    // .NET 2.0
    Assert.Throws<ArgumentException>( MethodThatThrows() );

    Assert.Throws<ArgumentException>(
	  delegate { throw new ArgumentException(); } );

    // Using C# 3.0	  
    Assert.Throws<ArgumentException>(
      () => throw new ArgumentException(); } );
  }
  
  void MethodThatThrows()
  {
    throw new ArgumentException();
  }

This example shows use of the return value to perform additional verification of the exception.

[TestFixture]
public class UsingReturnValue
{
  [Test]
  public void TestException()
  {
    MyException ex = Assert.Throws<MyException>(
      delegate { throw new MyException( "message", 42 ); } );
    Assert.That( ex.Message, Is.EqualTo( "message" ) );
    Assert.That( ex.MyParam, Is.EqualTo( 42 ) ); 
  }

This example does the same thing using the overload that includes a constraint.

[TestFixture]
public class UsingConstraint
{
  [Test]
  public void TestException()
  {
    Assert.Throws( Is.Typeof<MyException>()
                 .And.Message.EqualTo( "message" )
                 .And.Property( "MyParam" ).EqualTo( 42 ),
      delegate { throw new MyException( "message", 42 ); } );
  }

Use the form that matches your style of coding.

Exact Versus Derived Types

When used with a Type argument, Assert.Throws requires that exact type to be thrown. If you want to test for any derived Type, use one of the forms that allows specifying a constraint. Alternatively, you may use Assert.Catch, which differs from Assert.Throws in allowing derived types. See the following code for examples:

// Require an ApplicationException - derived types fail!
Assert.Throws( typeof(ApplicationException), code );
Assert.Throws<ApplicationException>()( code );

// Allow both ApplicationException and any derived type
Assert.Throws( Is.InstanceOf( typeof(ApplicationException), code );
Assert.Throws( Is.InstanceOf<ApplicationException>(), code );

// Allow both ApplicationException and any derived type
Assert.Catch<ApplicationException>( code );

// Allow any kind of exception
Assert.Catch( code );

See also...