Exception testing happens when we write test to assert that the code under test throws an exception when called with certain parameter. Since I started writing test, I have documented several steps which I can use to assert that my code under test throws a certain kind of exception. I even took to stackoverflow to see if I can get other people’s opinion on my approach and I’ll share my findings with you in this post.
To do this, I’ll be working with a tic tac toe game example that should throw exception when a null value is added to the game board. Below is my first approach:
//Arrange int index = 1; string value = null; //Act var ex = Assert.Throws(() => board.Add(key, value)); //Assert Assert.IsType(ex);
This approach calls the code under test and gets the result returned from calling the code through the Assert.Throws and later performs the actual assert by checking that the returned type is of ArgumentException. This approach makes it hard to determine the purpose of the test because, we’re having two assert operation here, and we don’t know if we’re testing for a matching type or expecting an exception. It is therefore, not advisable to have multiple assert in a test. If you find yourself in this situation, you should take a second look at that test and pick out code which you can create another test for. One aspect I’ve found this approach useful is if I want to do a detailed assert on the exception thrown e.g
- Check for a matching exception message:
- Assert that the inner exception is null:
My second approach combines the Act and Assert parts:
int index = 1; string value = null; //Assert Assert.Throws(() => board.Add(index, value));
This pattern combines the Act and Assert parts together (NUnit and xUnit supports this), making the test short and readable. This pattern is best if we do not need to perform detailed assert on the exception thrown.
On stackoverflow, jimmy keen suggested another approach which is closely related to the second approach above.
//Arrange int index = 1; string value = null; //Act Action addNullValue = () => board.Add(key, value); //Assert Assert.Throws(addNullValue);
This pattern tries to make the test readable as compared to my first approach by wrapping the code under test in an
Action delegate. This pattern is basically the same as the second, except that it wraps the code under test in a delegate which is passed to the
Assert.Throws method. But basically, the code under test is executed when
Assert.Throws is called.