Multiple asserts are good if you are testing more than one property of an object simultaneously. This could happen because you have two or more properties on an object that are related. You should use multiple asserts in this case so that all the tests on that object fail if any one of them fails.
Use two asserts in one test case. If the first assert fails, it's true, you won't know whether the second assert passed or not. But you're going to fix the code anyway, so fix it, and then you'll find out if the second assert passed. Write two tests, one to check each condition.
Likewise, a poor unit test can arise due to different attributes or practices, which should be avoided and may include: Non-deterministic factors in the code-base are problematic, since they are difficult to test; for example, time as an authentication factor in code can fail due to different time zones.
As others have pointed out, it's best to stick with one assert in each test in order to avoid losing information - if the first assert fails, you don't know whether the later ones would fail also. You have to fix the problem with less information - which might (probably will) be harder.
A very good reference is Roy Osherove's Art of Unit Testing - if you want to get started right with Unit Testing, you could do a lot worse than starting here.
Noting for future readers that this question and its duplicate Is it bad practice to have more than one assertion in a unit test? have opposite majority opinions, so read them both and decide for yourself.
My experience is that the most useful quantum of testing is not the assertion, but the scenario -- that is, there should be one unit test for a given set of initial conditions and method call, with as many assertions as are necessary to assert the expected final conditions. Having one unit test per assertion leads to duplicate setup or tortuous workarounds to avoid the duplication (such as the awful deeply nested rspec contexts that I'm seeing more and more of lately). It also multiplies tests, drastically slowing your suite.
As long as each assertion has a unique and identifying failure message you should be good and will sidestep any Assertion Roulette issues because it won't be hard to tell which test failed. Use common sense.
I have found a different argument to this question (at least for myself):
Use of multiple asserts is OK if they are testing the same thing.
For example, it's OK to do:
Assert.IsNotNull(value);
Assert.AreEqual(0, value.Count);
Why? - because these two asserts are not hiding the intention of the test. If the first assert fails, it means the second would fail too. And indeed, if we remove the first assert, the second assert fails (with null reference exception - !!!) anyway when the value
is null. If this was not the case, then we should not put these two asserts together.
So, this is wrong:
Assert.IsNotNull(value1);
Assert.IsNotNull(value2);
As I've mentioned above, if the first assert fails, there is no clear indication about the second assert - we would still want to know what happens to the second one (even if the first one failed). So, for this reason, these two asserts belong to two different unit tests.
Conclusion: putting one or more asserts, when done properly, becomes the matter of the preference - whether we want to see assertion exceptions in the test results, or do we want to see some other exceptions as well in particular cases.
It's best to stick with only one assert in each test to avoid Assertion Roulette.
If you need to set up the same scenario to test multiple conditions based on identical premises, it's better to extract the setup code to a shared helper method, and then write several tests that call this helper method.
This ensures that each test case tests only one thing.
As always, there are exceptions to this rule, but since you are new to unit testing, I would recommend that you stick with the one assertion per unit test rule until you have learned when it's okay to deviate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With