Multiple Asserts in Unit Tests – Is it bad?

Unit test code should be treated like first class code so it should be maintained and refactored to improve its qualities just like any other production code.

In test code one smell is having multiple asserts in a test method which usually indicates that the same test method may be testing multiple scenarios. Take the following example:

        [TestMethod]
        public void Divide_ShouldWorkCorrectly()
        {
            var calculator = new Calculator();

            Assert.AreEqual(2, calculator.Divide(4, 2));
            Assert.AreEqual(4, calculator.Divide(4, 1));
            MSTestExtensions.ExceptionAssert.Throws<DivideByZeroException>(() => calculator.Divide(4, 0));
        }
        

The method above test for 3 things in one go:

  • division of a number by a divisor
  • division by 1 (special case)
  • division by 0

The reason this is bad is because when a unit test fails we want to know what happened exactly. We want to pinpoint the bug as precisely as possible. But having 3 asserts one after the other defeats this purpose because if one assert fails (say the first) the other ones will not get run, thus depriving us from useful information given by the other two asserts. Are we really that dumb and were able to really messed up all the code for a simple operation as division or we just have a subtle bug that is easy to fix and is isolated to one specific set of inputs?

So for the example above the should have been 3 separate tests having just one assert call into each one.

Now lets look at another example:

        [TestMethod]
        public void GetInterestingCustomer_WithIdOne_ShouldReturnInterestingCustomer()
        {
            //arrange
            var customerService = new CustomerService();

            //act
            Customer customer = customerService.GetInterestingCustomer(1);

            //assert
            Assert.IsNotNull(customer, "The customer received is null");
            Assert.AreEqual(true, customer.IsInteresting);
        }
        

This one also has two asserts but is it testing multiple things? Well, no. The test verifies that the customer returned is an interesting one. The first asserts that check for null is merely a convenience one that avoids failing the test in NullReferenceException and allows us to provide a more concise and friendlier message. Also the failure reason is more precisely expressed, as often times a null reference exception could have been thrown for other reasons like a missing expectation on a mock for instance.

The main difference between the two test methods is that the second one tests conceptually just one thing while the first one tests for different conceptual things (division with a positive number and division by 0).

So in situations like the second one creating yet another unit test just for the first assertion might be a bit of overkill and if done repeatedly might turn into a maintenance problem later in the project.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s