C# – How to use Assert.ThrowsException

Use Assert.ThrowsException<T>() in a unit test to verify that the code throws a specific type of exception. Here’s an example of asserting that ArgumentNullException is thrown:

[TestMethod()]
public void WhenSentenceNull_ThrowsArgumentNullException()
{
	//arrange
	Utility utility = new Utility();

	//act & assert
	Assert.ThrowsException<ArgumentNullException>(() => utility.CountWords(null));
}
Code language: C# (cs)

You specify the type of exception you’re expecting and then pass in a lambda that calls the code you’re testing. The assertion succeeds if and only if the code throws the specific type of exception.

If you’re using the older ExpectedException attribute (or try/catch/assert manually), consider updating your tests to use Assert.ThrowsException<T>() instead.

The problem with ExpectedException

Before Assert.ThrowsException<T>() was available (starting in VS2017), your best option was to use the ExpectedException attribute. Chances are, if you’re maintaining a project, you’ll see this all over the place in the unit tests.

One of the main problems with ExpectedException is it asserts that the unit test throws an exception, instead of just asserting that the code under test throws an exception. This can lead to tests passing when they shouldn’t, which is really bad. Here’s an example:

[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);
	}
}
Code language: C# (cs)

The arrange section in the unit test (highlighted line) is throwing ArgumentNullException, so the test passes because that’s what ExpectedException is checking for. In other words, the test is passing when it shouldn’t. Switching this to using Assert.ThrowsException<T>() eliminates the problem. The difference is that Assert.ThrowsException<T>() only asserts against the code under test, not against the unit test as a whole.

Leave a Comment