Testing that an exception isn’t thrown in C#

In my previous post, Testing for exceptions in C#, I mentioned how to create an Assert Extension class to check that an exception is thrown, much like in NUnit.

You can also create a method to test that an exception isn’t thrown, be it a general or specific exception. NUnit includes such a method and in the interest of completion I will give an example.

Most of the time though, you should only be testing for the correct behavior or testing that a specific exception is being raised.

Almost every case where people are looking to test that a specific exception isn’t thrown can be changed and the changed tests will end up delivering better value.

With that out of the way, here is how you would implement it:

public static void DoesNotThrows<T>(Action expressionUnderTest, string exceptionMessage = "Expected exception was thrown by target of invocation.") where T : Exception
{
    try
    {
        expressionUnderTest();
    }
    catch (T)
    {
        Assert.Fail(exceptionMessage);
    }
    catch (Exception)
    {
        Assert.IsTrue(true);
    }

    Assert.IsTrue(true);
}

Here is how you would use it:

// Testing that no exception is being thrown
[TestMethod]
public void ExampleDoesNotThrows()
{
    int someInteger = 10;
    AssertExtension.DoesNotThrows<Exception>(() => someInteger.ToString());
}

// Testing that correct behavior will not throw an exception
[TestMethod]
public void ExampleDoesNotThrowsNoException()
{
    // Arrange
    var classUnderTest = new StringlyType();
    classUnderTest.Setup();
    int toStringlyfy = 1;

    // Act && Assert
    AssertExtension.DoesNotThrows<NullReferenceException>(() => classUnderTest.Stringlyfy(toStringlyfy));
}

// Testing that another exception than the one we expected isn't thrown
[TestMethod]
public void ExampleDoesNotThrowsWithSpecificType()
{
    // Arrange
    var classUnderTest = new StringlyType();
    int toStringlyfy = 1;

    // Act && Assert
    AssertExtension.DoesNotThrows<IndexOutOfRangeException>(() => classUnderTest.Stringlyfy(toStringlyfy));
}

You can refer to this previous post for more context on the test methods.

A DoesNotThrows method could be used to replace a test that does not have any asserts and whose only way of failing is through raising an exception.

In any case, when you are about to use a DoesNotThrows, stop and really think it through.

Testing for exceptions in C#

The traditional method to test for exceptions with the Microsoft unit testing framework is to use the ExpectedException attribute.

This method has shortcomings. The biggest is that it checks the whole method for the exception which can lead to false positives. Here is a contrived example to show what I am talking about.

The StringlyType class is by the way, not serious.

    // class under test
    public class StringlyType
    {
        private StringBuilder stringlyTypeBuilder = null;

        // contrived setup method
        public void Setup()
        {
            stringlyTypeBuilder = new StringBuilder();
        }

        public string Stringlyfy(object toStringlyFy)
        {
            stringlyTypeBuilder.Append(toStringlyFy.ToString());
            return stringlyTypeBuilder.ToString();
        }
    }

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void TraditionalExpectedException()
        {
            // Arrange
            var classUnderTest = new StringlyType();
            int toStringlyfy = 1;

            // Act
            classUnderTest.Stringlyfy(toStringlyfy);
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void TraditionalExpectedExceptionFalsePositive()
        {
            // Arrange
            var classUnderTest = new StringlyType();

            StringlyType randomClass = null;
            randomClass.Setup();

            int toStringlyfy = 1;

            // Act
            classUnderTest.Stringlyfy(toStringlyfy);
        }

The first test method will pass. We haven’t called the Setup method on StringlyType so the call to Append will throw our NullReferenceException.

On the second test method, we will get a false positive. The call to randomClass.Setup() will throw an exception and our test will be none the wiser. If we change the behaviour of StringlyType so that the StringBuilder is initialized in the constructor, the false positive will keep on telling us the code is throwing an exception.

A better way

NUnit, an open-source alternative to Microsoft’s framework, has been using a better approach for years. Their approach is having an Assert.Throws that works like an ordinary assert.

When I am in an environment that isn’t using NUnit I like to create something equivalent along the lines of:

public static class AssertExtension
    {
        public static T Throws<T>(Action expressionUnderTest,
                                  string exceptionMessage = "Expected exception has not been thrown by target of invocation."
                                 ) where T : Exception
        {
            try
            {
                expressionUnderTest();
            }
            catch (T exception)
            {
                return exception;
            }

            Assert.Fail(exceptionMessage);
            return null;
        }
    }

Since the Assert class is static we can’t create extension methods for it, hence I’m creating another AssertExtension class.

This AssertExtension class will allow to write the previous tests in the following way.

        [TestMethod]
        public void ExampleWithAssertThrows()
        {
            // Arrange
            var underTest = new StringlyType();
            int t = 1;

            // Act && Assert
            AssertExtension.Throws<NullReferenceException>(() => underTest.Stringlyfy(t));
        }

        [TestMethod]
        public void WillNotGetAFalsePositive()
        {
            // Arrange
            var underTest = new StringlyType();

            StringlyType randomClass = null;
            randomClass.Setup();

            int t= 1;

            // Act && Assert
            AssertExtension.Throws<NullReferenceException>(() => underTest.Stringlyfy(t));
        }

Notice that the second method we will not be a false positive.

This method has several advantages:

  • prevents false positives
  • easier to see which statement should throw an exception
  • more succinct and idiomatic than using a try catch
  • allows to return the thrown exception

Here is an example of the last point:

var thrownException = AssertExtension.Throws<InvalidOperationException>(
                      () => classUnderTest.Stringlyfy(toStringlyfy));

Assert.AreEqual("some message", thrownException.Message);

I made a GitHub Gist if you want to get/modify the AssertExtension class.

C# Exception best practices

Here are some good practices for dealing with exceptions in C#, and by extension .Net. While the post title says best practices, I’m using the term good practice here because I do not have the pretension that these are the best practices available or that all best or good practices are presented herein.

Why use the word best rather than good in the title? I’d be surprised if anyone searched google for exception good practices, that’s why.

Here they are.

Don’t use ApplicationException

ApplicationException was created as a standard base class from which all our applications custom exceptions should derive from. All framework system exceptions would derive from SystemException. This was made to allow us for instance, to catch only our application’s exception.

There are three problems with this premise. First, the rule was not followed. Some exceptions like System.Reflection.TargetInvocationException or System.Threading.WaitHandleCannotBeOpenedException derive from ApplicationException (there’s a total of eight of them), which means you can’t use the fact that an exception derives from ApplicationException to differentiate it as one of your own.

The MSDN documentation about ApplicationException and Best Practices for Handling Exceptions both proscribe using it for another reason.

The second point against ApplicationException, as brought by these links, is that differentiating application exceptions has been shown to be of little value. I agree with this. If I have a method that can throw a custom exception or a framework exception (ie: an exception from a .Single() LINQ extension method), I will want to handle both in the same way.

Third, I have often seen people use ApplicationException directly rather than derive from it. This leads to people being lazy and using the generic ApplicationException (which is about the same as using Exception) rather than a more precise one, like ArgumentNullException or ArgumentOutOfRangeException for example.

Also Krzysztof Cwalina on his blog declared the exception as useless: ApplicationException considered useless. If you haven’t heard about Cwalina, he’s a principal architect on the .NET Framework team.

Rethrowing Exceptions

If you need to rethrow an exception in your catch block this is the right way to do it:

// correct way to rethrow an exception
try
{
    Foo(); // Foo calls Bar which throws InvalidOperationException
}
catch (Exception exception)
{
    // do stuff 
    throw;
}

as opposed to this:

// wrong way to rethrow an exception
try
{
    Foo(); // Foo calls Bar which throws InvalidOperationException
}
catch (Exception exception)
{
    // do stuff 
    throw exception;
}

The only change is on the line that throws the exception.

The difference is that in the first version the callstack is preserved where in the second version it starts where the method is called.

Compare the two:

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Operation is not valid due to the current state of the object.
  Source=ExceptionBlog
  StackTrace:
       at ExceptionBlog.Exception1.Bar() in \...\Exception1.cs:line 12
       at ExceptionBlog.Exception1.Foo() in \...\Exception1.cs:line 17
       at ExceptionBlog.Exception1.Rethrow() in \...\Exception1.cs:line 28
       ...

and

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Operation is not valid due to the current state of the object.
  Source=ExceptionBlog
  StackTrace:
       at ExceptionBlog.Exception1.Rethrow() in \...\Exception1.cs:line 28
       ...

Don’t use exceptions as a control flow mechanism

Reserve exceptions for exceptional and unexpected situations. Sometimes you will see exceptions being used as a control flow mechanism, just like if statements.

For example, say you have a system that handles employee records. In the vast majority of cases employees will be 16 years or older. In rare situations in your business domain you have special cases where an employee is younger than this. In these case your system must show a warning that the employee must get a parent/tutor approbation before signing a certain document.

Here you could use an exception that deals with those rare cases. The thing is you know these cases can happen and you expect them to happen infrequently.

In these cases using a normal control flow statement rather than an exception is more idiomatic and often clearer to the reader. Exceptions are also slower than control flow statements. Finally in this example you will be treating a business case in the exception handling code. It is better to separate the two concerns.

Using the same base example, a situation that would merit an exception is the system receiving an employee id and not being able to return an employee from the data source with said id.

Exception variable name

This next one may seem very minor. In some sense it is, but this is the kind of subtle detail that adds up and help make code cleaner.

We aren’t writing code for computers but for human readers. The computer is fine with assembler. We as writers and readers of code are better off with a higher level language. Not only for the level of abstraction it provides but for the higher maintainability of readable code. Readability is important.

Readable code is faster to comprehend and easier to discuss aloud with colleagues. This is why abbreviations and acronyms in variable names should be avoided.

Even with proponents of self documenting code, there are some areas that are sometimes ignored. The name of the exception variable is one of those.

catch (Exception e)

While e or ex is understood by anyone, why not put in the extra effort to at least write

catch (Exception exception)

or better yet an even better and more descriptive name. With auto complete you will just have to type it in once anyway.