One assertion per test should come natural

Posted by Chris on November 17, 2006

In an “earlier post”:/articles/2006/10/22/to-setup-or-not-to-setup I mentioned very briefly the _one-assert-per-test-method_ rule. This is something I think originally came from Dave Astels and definitely a guideline that I try to follow. The reason is of course that it helps make tests simpler and more expressive and therefore make them more helpful in locating problems. “Astels also argue”:http://www.artima.com/weblogs/viewpost.jsp?thread=35578 that “_by adding the specification of the behavior one tiny piece at a time, you drive toward evolving the code in small, controllable, understandable steps_”.

Now there might of course be situations when it makes sense to have more than one assert. However, what is important to note about those situations is that they should not change the Arrange-Act-Assert structure of a test. So if there are multiple asserts in a test, they should all be at the end of the test. Definitely do not let your tests become Arrange-Act-Assert-Act-Assert-Act-Assert or similar.

However, even with nicely structured tests, I have come to think of multiple asserts as a kind of smell that the test (or rather the fixture) might not be really thought through. There is one specific situation that I have seen a couple of times where people say that the test is so simple that there is no reason to write it in multiple test methods. Let me show a typical example:

[TestFixture]
public class FooBuilderTests
{
  [Test]
  public void FooIsBuiltCorrectly()
  {
    string fooThis = "foobar";
    string fooThat = "barfoo";
    FooBuilder fooBuilder = new FooBuilder();
    Foo foo = fooBuilder.Create(fooThis, fooThat);

    Assert.AreEqual(fooThis, foo.This);
    Assert.AreEqual(fooThat, foo.That);
  }
}

What we are testing is a simple builder class (FooBuilder) that is used to create object instances of the class Foo. It takes two strings which we expect to be set correctly on the appropriate properties of the Foo instance returned. Simple enough, right? Why would we ever want to create two separate test methods for these two asserts that are so linked to each other?

As I said, I smell something wrong here. And it is very obvious to me what it is. FooBuilderTests is not a good name for a test fixture, or rather the fixture is not a good one. We should not simply have a single “generic” fixture for every production class. What the fixture is all about is setting up everything in a specific state and then testing things in that state. So what would be a better fixture in this case? Look at the setup that is common for the tests that will be in the fixture. How about we call it AFooCreatedByAFooBuilder. This also makes it quite natural to use the setup method of xUnit frameworks, as I discussed in the “post mentioned earlier”:/articles/2006/10/22/to-setup-or-not-to-setup, although it of course works equally well to do setup in a method called directly from the test methods. Here is what this fixture would look like:

[TestFixture]
public class AFooCreatedByAFooBuilder
{
  private Foo foo;
  private string fooThis = "foobar";
  private string fooThat = "barfoo";

  [SetUp]
  public void InitPerTest()
  {
    FooBuilder fooBuilder = new FooBuilder();
    foo = fooBuilder.Create(fooThis, fooThat);
  }
}

With this fixture it becomes quite natural to create two separate tests for the two asserts. Here is the code that goes for the tests:

  [Test]
  public void ThisIsSetCorrectlyOnFooInstance()
  {
    Assert.AreEqual(fooThis, foo.This);
  }

  [Test]
  public void ThatIsSetCorrectlyOnFooInstance()
  {
    Assert.AreEqual(fooThat, foo.That);
  }

If we strive to organize our tests in a fixture oriented approach instead of a per-production-class oriented approach, I think having one assert per test method comes natural. By the way, with Behavior-Driven Development I do not think this would ever be an issue. With the contexts and specifications of BDD we write this way naturally. Even though BDD is not really a lot more than a different wording from TDD, it makes it so much easier to think correctly about writing your tests/specifications.