Bradley Braithwaite
1 import {
2 Learning,
3 JavaScript,
4 AngularJS
5 } from 'Brad on Code.com'
6 |
Check out my online course: AngularJS Unit Testing in-depth with ngMock.

Asserting Exceptions in MSTest with Assert.Throws()

I wanted a better way of asserting exceptions in MSTest.

on
on Aesthetics, MSTest, TDD

I’ve been creating a LOT of unit tests using MSTest recently. I always layout tests using the Arrange, Act, Assert. Here is a simple example of how I would typically layout a test:

[TestMethod]
public void AddMutlipleNumbersReturnsTheSumOfNumbers()
{
    // Arrange
    StringCalculator sc = new StringCalculator();

    // Act
    int sum = sc.Add("1,2");

    // Assert
    Assert.AreEqual(3, sum);
}

An irritant I have with MSTest is the way it asserts expected exceptions. Currently you have to decorate your test using an Attribute as follows:

[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void AddWithNegativeNumberThrowsArgumentOutOfRangeException()
{
    // Arrange
    StringCalculator sc = new StringCalculator();

    // Act
    int sum = sc.Add("-1");

    // Assert - Expects exception
}

Note how the Assert section of the test is now empty. I typically add a comment here just to highlight the fact that the attribute is actually asserting the presence of the exception but… the reduced readability and inconsistency of this approach bothers me.

You could assert the exception a little more explicity (verbosly!) as per the following code snippet, but that would just be upsetting and would result in an unnecessary amount of duplicate code and lots of tests that are not so easy to read:

[TestMethod]
public void AddWithNegativeNumberThrowsException()
{
    // Arrange
    StringCalculator sc = new StringCalculator();
    Exception expectedExcetpion = null;

    // Act
    try
    {
        int sum = sc.Add("-1");
    }
    catch (Exception ex)
    {
        expectedExcetpion = ex;
    }

    // Assert
    Assert.IsNotNull(expectedExcetpion);
}

This bothered me enough that I spent a few hours writing a simple class which provides an implementation that is very similar to the Throws method that NUnit users will know and love.

The Concept

This implementation provides a way of asserting there is an exception using the syntax below. I prefer this style since all the actions and assertions are now within the body of the test.

[TestMethod]
public void AddWithNegativeNumberThrowsException()
{
    // Arrange
    StringCalculator sc = new StringCalculator();

    // Act => Assert
    ExceptionAssert.Throws(() => sc.Add("-1"));
}

Assert for a specific type of exception would look as follows:

[TestMethod]
public void AddWithNegativeNumberThrowsArgumentOutOfRangeException()
{
    // Arrange
    StringCalculator sc = new StringCalculator();

    // Act => Assert
    ExceptionAssert.Throws<ArgumentOutOfRangeException>(() => sc.Add("-1"));
}

Checking that an exception has an expected error message would read:

[TestMethod]
public void AddWithNegativeNumberThrowsExceptionExpectedMessage()
{
    // Arrange
    StringCalculator sc = new StringCalculator();

    // Act => Assert
    ExceptionAssert.Throws(() => sc.Add("-1"), "you cannot supply negative numbers.");
}

Checking that an exception has an expected error message that contains:

[TestMethod]
public void MethodThrowsExceptionWithPartiallyMatchingExceptionMessage()
{
     // Arrange
     const string expectedMessage = "Parameter name: username";

     // Act & Assert
     ExceptionAssert.Throws(() => { throw new ArgumentNullException("username"); }, expectedMessage, ExceptionMessageCompareOptions.Contains);
}

###The Implementation

You can download the full source code from Github. For a quick overview of the code the main body of the Throws() method looks as below:

public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
 {
     try
     {
         task();
     }
     catch (Exception ex)
     {
         AssertExceptionType<T>(ex);
         AssertExceptionMessage(ex, expectedMessage, options);
         return;
     }
     if (typeof(T).Equals(new Exception().GetType()))
     {
         Assert.Fail("Expected exception but no exception was thrown.");
     }
     else
     {
         Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
     }
 }

The key part is the first parameter of Action. Using this will accept any Action (method) but will also act as a wrapper so we can pass a Func (function) without having to provide an overloaded Throws() method signature for passing functions with n number of arguments.

By using a lambda expression in the test as illustrated below the method or function is wrapped in an Action delegate which delays invocation. ExceptionAssert.Throws(() => sc.Add(“-1”)); This allows us to invoke the actual method or function inside the Throws() method and it also mitigates the need to create a bunch of different overloaded Throws() method signatures that would accept the various function delegates.

###Taking things further

The remaining inconsistency is that the standard methods to assert in MSTest begin with Assert. e.g. Assert.IsTrue(1 == 1);. The implementation I proposed previously would read ExceptionAssert.Throws(() => something);, which is an improvement upon the use of the attribute, but it could be better. I went a step further and created an extendible wrapper that allows the Assert class from the MSTest assembly to be extended. There are some complexities to this which will come in another blog post, but the result is we can now use the following syntax to assert an exception in MSTest:

Assert.Throws(() => sc.Add("-1"));

This extendible wrapper means that you can also add your own extension methods to the Assert class and all the standard methods from the MSTest implementation are unaffected.

See the follow up post with more detail on how to extend MSTest.

Get the Source Code

Source code for MSTestExtensions.

####Download from Nuget

PM> Install-Package MSTestExtensions

See the Nuget project page for MSTestExtensions.

SHARE
Don't miss out on the free technical content:

Subscribe to Updates

CONNECT WITH BRADLEY

Bradley Braithwaite Software Blog Bradley Braithwaite is a software engineer who works for search engine start-ups. He is a published author at pluralsight.com. He writes about software development practices, JavaScript, AngularJS and Node.js via his website . Find out more about Brad. Find him via:
You might also like:
mean stack tutorial AngularJS Testing - Unit Testing Tutorials