C# – Use Assert.ThrowsException instead of ExpectedException attribute

If you’re using the built-in MSTest unit testing framework, you may be used to the old way of asserting exceptions by using the [ExpectedException] attribute. The following example illustrates one of the key problems with this approach:

[TestClass()] public class UtilityTests { Dictionary<string, string> sentenceMap = new Dictionary<string, string>() { {"null", null } }; [TestMethod()] [ExpectedException(typeof(ArgumentNullException))] public void WhenSentenceNull_ThrowsArgumentNullException() { //arrange Utility utility = new Utility(); string sentence= sentenceMap[null]; //act utility.CountWords(sentence); } }

The ArgumentNullException is being thrown, so the test passes. However, the exception is being thrown in the arrange section on the highlighted line. In other words, the test is falsely passing, which is very, very bad.

If you’re following the TDD approach, you would be suspicious of a test initially passing. If you’re not following the TDD approach, you may see this test is passing and be lured into a false sense of security.

Introducing Assert.ThrowsException()

Instead of using the [ExpectedException] attribute, I changed the test to use Assert.ThrowsException().

[TestMethod()] public void WhenSentenceNull_ThrowsArgumentNullException() { //arrange Utility utility = new Utility(); string sentence = sentenceMap[null]; //act Assert.ThrowsException<ArgumentNullException>(() => utility.CountWords(sentence)); }

This test is now failing as expected due to the bug in the arrange section. This is exactly what I want. Now I know I need to fix the bug in the test itself.

They added Assert.ThrowsException in VS2017. This is part of Microsoft.VisualStudio.TestTools.UnitTesting. I only wish they had removed the [ExpectedException] attribute, or had started showing a build warning if you’re using it. Many people are simply used to using this attribute and may not be aware that Assert.ThrowsException was added.

Leave a Comment