Search The Blog
Latest Posts
from 5whys.com
Twitter: @RoyOsherove
About this site

TDD in .NET Online Course

TDD and BDD in Ruby Online Course

 

Subscribe!

This site aims to connect all the dots of my online activities - from tools, books blogs and twitter accounts, to upcoming conferences, engagements and user group talks.

« Now *that's* how you tell a wedding proposal story! | Main | Setting Up VirtualMock in the Eclipse IDE »
Thursday
Apr142005

Try to avoid multiple asserts in a single unit test 

Consider Assert failures as symptoms of a disease and Asserts as indication points or blood checks for the body of the software. The more symptoms you can find, the easier the disease will be to figure out and remove. If you have multiple asserts in one test - only the first failing one reveals itself as failed and you lose sight of other possible symptoms.
 
 
 
I've written about this before but I want to stress this again because this topic is more important than you might think.
 
Void Sum_AnyParamBiggerThan1000IsNotSummed()

   Assert.AreEqual(3, Sum(1001,1,2); 
   Assert.AreEqual(3, Sum(1,1001,2); 
   Assert.AreEqual(3, Sum(1,2,1001);
}
 
There are several disadvantages to using multiple asserts in one test case.
The main one is this:

Sometimes you get a better  idea of what's wrong with the code if you have multiple test failures.
 
When you have multiple asserts in one single test, only the first one fails and the test execution stops for this test case. The rest of the lines in the test code never get checked - you're losing some more points of view (symptoms) that you might consider important in order to quickly discover where the problem stems from.
 
Another example - you're changing a piece of code and suddenly 6 tests that might seem unrelated break. If you're lucky you might realize that these tests all have one thing in common - they use some common object or method that does not work anymore. That is - it's easier to realize that the problem probably does not lie within the tests  - they are correct and logical,  but their failure is merely a symptom of a deeper problem that needs attention.
 
Now assume the same scenario with only one test failing - a test with multiple asserts.
Since you now see only one "symptom" you might "diagnose" the disease wrongly because you don't have all the facts. That means you'll probably spend more time investigating this problem and struggling with it  -- one of the things I see most often in these cases is this:
 
once you make one assert pass somehow, another one "reveals" itself in the same test and fails as well. You don't get the big picture and have to realize it step by step--Along the way you you might even make "corrections" to the code which might not have been needed but "fixed" it from a different view - fixed the symptom but not the problem. You might have introduced more changes to the system and even made it less stable in the process - all the while taking more precious time.
 
 
More notes to consider:
 
If I was writing this test after  the production code was already written, I might not have a problem with this in some situations (pressed for time etc..). But if this test is written before the tested code is written, it might prove less optimal for several reasons:
 
 You'll  spend a longer amount of time writing code to make the test pass.
   The longer you spend without running tests, the less confident you become.
 
 
You're not focusing on a small problem anymore.
You're focusing on a combined, larger problem, more generic  which should be solved ("this and this and this should all pass at once"). It's easy to get stuck on large problems. It's  easier to keep going while continually solving small problems one after the other.
 
 
 
The more time you spend not running the tests, the more code you write that has not been tested,
and which will probably depend on more code that has not been tested. You re more likely to present unforeseen bugs.
The previous paragraph should not come as a surprise because the more code you write between each unit tests, the smaller the likelihood that your test actually covers that code. That s because:
 
 
 
Trying to make a test with three ASSERTs pass, is just like trying to make three separate test cases pass in a single bounce:
You'll have to write more code that handles more cases and you ll probably end up writing it more generic that you would have if you were just trying to fix one test case at a time. You won't really know if your tests cover all the generic code you've just written as you would have known by making the tests pass one by one, in the simplest way possible.
 
 
 
Once you have multiple ASSERTs in a test case, it's very easy and human to keep adding more asserts into the existing test than it would be to add them using new tests. Even if those were totally different asserts in nature, the broken window theory works very well here, and leads to less maintainable and less readable tests.
 
   
 
You're working more time without the "success" feedback of the green bar.
Like it or not, the psychological effect here is important. It leads to a better coding experience and more confidence and happiness at work.
 
 
Hopefully all of these reasons should make you think twice before just jumping in without attention to your tests. You'd be surprised at how fast these symptoms add up to make the testing experience either easier and faster or much more repetitive and painful that it could have been.

PrintView Printer Friendly Version

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
Web Analytics