BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Testing
.NET 1.1+

NUnit Expected Exceptions

When code enters an unexpected state, or when a member is called with invalid parameters, it is usual to throw an exception. When writing unit tests, the test code should ensure that the correct exceptions are thrown.

Testing For Exceptions

In a previous article, as part of the Automated Unit Testing tutorial, I explained the use of the NUnit Exception assertions. These allow you to test that specific code, provided using a delegate or lambda expression, throws an specific exception or an exception of a derived type. You can also test that a code fragment executes without raising an exception.

Another way to check for an exception being thrown is to use NUnit's ExpectedException attribute. This attribute is applied to a test method in addition to the Test attribute. The simplest form of the attribute requires a single parameter containing the type of the exception that is expected. If no exception is thrown, or if the type of the exception is of a different type, the test fails.

The following code shows three tests. The first passes as the correct exception is thrown. The second fails as it does not generate an exception. The third fails because the exception is of the incorrect type, even though ArgumentNullException is a subtype of the expected ArgumentException.

[Test, ExpectedException(typeof(ArgumentException))]
public void PassingTest()
{
    throw new ArgumentException();
}

[Test, ExpectedException(typeof(ArgumentException))]
public void FailingTestNoException()
{
    // No throw
}

[Test, ExpectedException(typeof(ArgumentException))]
public void FailingTestWrongType()
{
    throw new ArgumentNullException();
}

Providing the Exception Type as a String

In the current version of NUnit, you can elect to provide the fully qualified name of the expected exception as a string. This means that you do not have to add a reference to the assembly that declares the exception. However, you must ensure that you enter the name accurately as misspelling the exception name will give invalid test results.

The following test checks for a SoapException being thrown without the need to reference the System.Web.Services DLL.

[Test, ExpectedException("System.Web.Services.Protocols.SoapException")]
public void TestByName()
{
}

Checking the Exception Message

A common problem when testing that exceptions are thrown correctly is that an unhandled exception may be thrown by a method called by the class under test. If this exception is of the expected type, it will allow the test to pass even if the code under test is not functioning correctly. To alleviate this problem you can elect to check the message property of the exception and fail the test if it does not meet given criteria.

To check the exception message you can use the two named parameters, ExpectedMessage and MatchType. The first allows you to provide the text that you wish to compare with the thrown exception. The second lets you select the type of comparison to make, using one of the following constants from the MessageMatch enumeration:

  • Exact. Specifies that the expected message and the actual message must match exactly. If the MatchType parameter is excluded from the attribute, this option is the default.
  • StartsWith. The exception's message must start with the provided text.
  • Contains. The exception's message must contain the specified text.
  • Regex. The exception's message must match the regular expression in the ExpectedMessage parameter.

The following four methods show passing tests for each match type:

[Test, ExpectedException(typeof(ArgumentException),
    ExpectedMessage = "Invalid Form Entry", MatchType = MessageMatch.Exact)]
public void PassingExactTest()
{
    throw new ArgumentException("Invalid Form Entry");
}

[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Invalid",
    MatchType = MessageMatch.StartsWith)]
public void PassingStartsWithTest()
{
    throw new ArgumentException("Invalid Form Entry");
}

[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Form",
    MatchType = MessageMatch.Contains)]
public void PassingContainsTest()
{
    throw new ArgumentException("Invalid Form Entry");
}

[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = @"([A-Za-z0-9\-]+)",
    MatchType = MessageMatch.Regex)]
public void PassingRegexTest()
{
    throw new ArgumentException("Invalid Form Entry");
}

User Messages

As with assertions, it can be beneficial to add a custom message when a test fails. With the ExpectedException attribute, you can add the UserMessage named parameter and a string to display for a failed test. For example:

[Test, ExpectedException(typeof(ArgumentException),
    UserMessage="Argument exception not thrown for invalid data")]
public void CustomMessageTest()
{
}

When this test is executed, the failure is reported with the custom message and the detail of the problem, as follows:

CustomMessageTest:
Argument exception not thrown for invalid data
System.ArgumentException was expected
8 June 2011