Single Assert Reconsidered

Last updated: May 15 2005

sven.gorts@refactoring.be

Abstract: A single assert per test is generally considered good unit testing practice. Yet there are times when I prefer to deviate from this rule.

Introduction

Having a single assertion per test is a widespread and often recommended JUnit testing practice. In day-to-day development I generally try to ensure my tests comply to the single assert per test rule, but there are times when I deviate. Most of the time this means there are troubles.

A Single Assert

Now before we continue let me explain what I mean by a single assert. A single assert should not be taken to literally like a single assertTrue() or assertEquals() call, but rather as a single block of asserts that verify the postcondition of the test. For example:

  // complies single assert rule 
  public void testAdditionOneElement() { 
    ProprietaryList list = new ProprietaryList(); 
    list.add(new Object()); 
    assertFalse(list.isEmpty()); 
    assertEquals(1, list.size()); 
  }

A simple check to verify whether a test complies the single assertion per test rule is to see whether you can extract all of the asserts without any of the production code under test into a single assert method that directly queries the object under test. When able to do so, the test complies. From the test above for example we can easily extract the following assert method.

  private void assertListContainsOneElement(ProprietaryList list) { 
    assertFalse(list.isEmpty()); 
    assertEquals(1, list.size()); 
  }

An example of a test that violates the single assert per test rule is given below. We can't extract an assertion method as above, and at the same time ensure that the instance under test is queried directly.

  // violates the single assert rule 
  public void testAddition() { 
    ProprietaryList list = new ProprietaryList(); 
    list.add(new Object()); 
    assertEquals(1, list.size()); 
    list.add(new Object()); 
    assertEquals(2, list.size()); 
    list.add(new Object()); 
    assertEquals(3, list.size()); 
  }

Luckily tests like this one can easily be upgraded to tests that comply to the single assert per test rule. It's an easy trick, just split it up into separate tests for each size.

Parts Of A Test

A well written JUnit test consists of different parts, the last of those parts being the single assert block. For the scope of this article I will refer to these parts as setup, action and validation. Setup is the part where you set up the scene, preparing the test. Action is the part of performing the test. And validation, finally is the part where we validate or assert the correct behavior of the instance under test. So for the given example, what are these parts ?

  // what are setup, action and validation ? 
  public void testRemoval() { 
    ProprietaryList list = new ProprietaryList(); 
    Object instance = new Object(); 
    list.add(instance); 
    list.remove(instance); 
    assertFalse(list.contains(instance)); 
  }

First time pairing with someone it usually doesn't take long before my pair interrupts me to ask why I enter blank lines at certain points in the tests and remove them at other places. When doing so I 'm visually separating the setup, action and validation parts. So applied to the example above the test would now look as below. Setup, action, validate.

  public void testRemoval() { 
    ProprietaryList list = new ProprietaryList(); 
    Object instance = new Object(); 
    list.add(instance); 
 
    list.remove(instance); 
 
    assertFalse(list.contains(instance)); 
  }

While visually separating the different parts of a test may seem a bit overkill for tests this size I've found it really helpful in practice. Working with larger tests that need some cleanup, separating the different parts is what I usually start with.

We Need Confidence

Writing all unit tests with a single assert is all fine and neat but a bit idealistic. At times when things get though, when I find myself working on the code from "some guy who left", slaying dependencies and other dragons on the road, I often seek more confidence.

In presence of all kinds of bad side-effects, the extra confidence I want is an explicit verification of the setup. As such the test scheme becomes setup, check, action and validate. The check part being an extra assert block prior to the action part. Rewriting the test from the last paragraph yields:

  public void testRemoval() { 
    ProprietaryList list = new ProprietaryList(); 
    Object instance = new Object(); 
    list.add(instance); 
 
    assertTrue(list.contains(instance)); 
 
    list.remove(instance); 
 
    assertFalse(list.contains(instance)); 
  }

With an extra assert for verifying the setup in place the resulting test clearly violates the single assert per test rule as we described before. Question is whether this is a bad thing.

After all, we know the assertTrue(list.contains(instance)); merely serves to check the precondition of the test while assertFalse(list.contains(instance)); serves to validate its postcondition. Preconditions and postconditions, I have an idea.

A Different View

Reconsidering our unit testing scheme in terms of preconditions and postconditions exactly what is the meaning of the single assert per test rule ? The example is toy code anyway so lets refactor it to reflect this new insight.

  public void testRemoval() { 
    ProprietaryList list = new ProprietaryList(); 
    Object instance = new Object(); 
    list.add(instance); 
 
    preconditionTrue(list.contains(instance)); 
 
    list.remove(instance); 
 
    postconditionFalse(list.contains(instance)); 
  }

From the given code example it is apparent that the single assert per test we've discussed so far, corresponds to the verification of the postcondition while the setup check we've added is an explicit verification of the precondition.

Now I assume the idea behind having a single assert per test is to have a test setup simple enough to make its preconditions clear. For most of my tests checking the postcondition is indeed sufficient. Working on less ideal code explicit precondition checks often prove useful additions to get code working and covered.

Are these two in conflict ? Well, maybe. Taken literally these are in conflict but I believe the intent of the single assert per test rule is to test for a single postcondition each test. After all, in absence of precondition checks the two correspond. For me single assert per test is expressed a bit inaccurately and could better be expressed as test for a single postcondition.

Conclusion

Although the "single assert per test" principle is a good directive to start with its expressed a bit inaccurately. When I deviate from this principle its usually in favor of a style that explicitly verifies preconditions. I believe a more accurate version of the principle would be to verify a single postcondition per test.