42

Is there anything wrong with checking so many things in this unit test?:

ActualModel = ActualResult.AssertViewRendered()        // check 1
                          .ForView("Index")            // check 2
                          .WithViewData<List<Page>>(); // check 3

CollectionAssert.AreEqual(Expected, ActualModel);      // check 4

The primary goals of this test are to verify the right view is returned (check 2) and it contains the right data (check 4).

Would I gain anything by splitting this into multiple tests? I'm all about doing things right, but I'm not going to split things up if it doesn't have practical value.

I'm pretty new to unit testing, so be gentle.

Michael Haren
  • 105,752
  • 40
  • 168
  • 205
  • Some more discussion on the subject: http://stackoverflow.com/questions/831390/multiple-asserts-in-single-test and http://stackoverflow.com/questions/762512/unit-testing-question – Alconja Mar 12 '10 at 04:32
  • All good answers (all upvoted), thanks! – Michael Haren Mar 20 '10 at 17:25
  • See also http://programmers.stackexchange.com/questions/7823/is-it-ok-to-have-multiple-asserts-in-a-single-unit-test# – CAD bloke Jul 09 '14 at 21:52
  • The idea that each test case should have only one assert [is foolish](http://stackoverflow.com/a/20300843/545127). – Raedwald Apr 05 '16 at 11:45

6 Answers6

31

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.

Bevan
  • 43,618
  • 10
  • 81
  • 133
  • 2
    I found that book very good. It improved the quality of my unit tests tremendously. And while most books on software development are very thick, this book contains about 270 pages. This makes it great to put on your team's must-read list. And if you're in a hurry, Roy advices you to read only chapter 7. – Steven Mar 12 '10 at 11:57
  • The information preservation criterion is key. If the tests are executed in such a way that we're informed of which line fails, the criterion only requires that each assert gets its own line. – J.G. Oct 05 '20 at 15:45
13

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.

Community
  • 1
  • 1
Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
8

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.

John K
  • 28,441
  • 31
  • 139
  • 229
  • 5
    The problem with having multiple asserts isn't with telling which one failed - in most cases you get the line number, if nothing else. The problem is that you don't get to see if later tests would also fail, so you end up with less information about the bug. In some cases this isn't significant - but in some (most, in my experience, before I learnt this lesson) it is. – Bevan Mar 13 '10 at 04:48
  • 2
    *is that you don't get to see if later tests would also fail* but that's not relevant. You fix one Assert at a time. It's also safe to assume that if the first Assert is failing, the next will fail as well because previous conditions are not met. In my tests I replace most 'if' statements with an Assert. Aside from when a branch is valid (which is almost never the case). – Steffen Winkler Feb 20 '15 at 07:32
  • I disagree. If you have three different tests and run them all, you'll be able to see what asserts passed and what didn't. The more information you have when trying to fix something, the better off you'll be. You can make more precise changes to fix what's broken. – Jesse Moreland Oct 05 '16 at 21:50
8

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.

Tengiz
  • 8,011
  • 30
  • 39
2

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.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
0

I know that this is an old question but I thought I'd add my bit.

Generally I'd have as few assertions as possible in each test case. Tests can be often be written to save having lots of different assertions.

Suppose I have unit tests for a method which creates a salutation (eg Mr Smith) from the components of a name. I want to check this with a large number of different scenarios, it is unnecessary to have a separate test for each.

Given the following code, there are many different assertions. When they fail you can fix them one at a time until the assertions stop.

Assert.AreEqual("Mr Smith", GetSalutation("Mr", "J", "Smith"));
Assert.AreEqual("Mr Smith", GetSalutation("Mr", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "J", "Smith"));

An alternative to this is to keep a count of issues and assert this at the end.

int errorCount = 0;
string result;

result = GetSalutation("Mr", "J", "Smith");
if (result == "Mr Smith")
    errorCount++;

result = GetSalutation("Mr", "John", "Smith");
if (result == "Mr Smith")
    errorCount++;

Assert.AreEqual(0, errorCount);

In a real world situation I'd probably add some Trace commands to write the detail of the individual tests which failed to the output window

timbo
  • 63
  • 6