Caution, this blog may be ironically named

Multiple Asserts

| Comments

I’ve read many books and blogs that advocate only having one assert in a unit test and lots of people take that to mean literally assert statement.  I’ve always disagreed with taking it literally, I’ve always thought of it as one logical assert, as in you assert one concept at a time which could lead to multiple assert statements.

The main arguments against having more than one assert statement seems to be it’s not as readable and it’s sometimes difficult to understand what is failing because of it.  My normal response is to create my own asserts that accurately describe what the multiple asserts do and hide the real asserts in there.  For example:

   1: public void AssertIsValidClone(Customer oldCustomer, Customer actualCustomer)

   2: {

   3:     Assert.AreNotSame(oldCustomer, actualCustomer);

   4:     StringAssert.AreEqual(oldCustomer.Name, actualCustomer.Name);

   5:     StringAssert.AreEqual(oldCustomer.Address, actualCustomer.Address);

   6: }


   8: [Test]

   9: public void Clone_ValidCustomer_ValuesAreTheSameReferenceIsDifferent()

  10: {

  11:     //Some setup


  13:     var result = aCustomer.Clone();


  15:     AssertIsValidClone(aCustomer, result);


  17: }

Ok so this is a very contrived example but we can clearly see what the intent of the assert is rather than having several making it harder to understand. But what this doesn’t do is address the second concern. IE anyone of those three asserts could fail, so we fix it then the next fails, etc.

Enter an nUnit plug in called OAPT, this allows you to have multi asserts that generate multi unit tests in the runner so you can see exactly what is failing.  I won’t warble on too much about the details because it’s all in the link But let’s just rewrite our unit test:

   1: [Test, ForEachAssert]

   2: public void Clone_ValidCustomer_CloneIsNewItemWithValidData()

   3: {

   4:     //some setup


   6:     var newCustomer = originalCustomer.Clone();


   8:     AssertOne.From(

   9:         () => Assert.AreNotSame(originalCustomer, newCustomer)

  10:         () => StringAssert.AreEqual(originalCustomer.Name, newCustomer.Name)

  11:         () => StringAssert.AreEqual(originalCustomer.Address, newCustomer.Address));

  12: }

Much more concise and it will run as three separate tests.  I still do have an issue with it though, each test uses the test name with an appended number. It would be nice if you could pass in some text for it to append.  But then again it is open source so maybe I could add that feature myself :)