Tests should fail for one reason only, but that doesn't always mean that there should be only one Assert
statement. IMHO it is more important to hold to the "Arrange, Act, Assert" pattern.
The key is that you have only one action, and then you inspect the results of that action using asserts. But it is "Arrange, Act, Assert, End of test". If you are tempted to continue testing by performing another action and more asserts afterwards, make that a separate test instead.
I am happy to see multiple assert statements that form parts of testing the same action. e.g.
[Test]
public void ValueIsInRange()
{
int value = GetValueToTest();
Assert.That(value, Is.GreaterThan(10), "value is too small");
Assert.That(value, Is.LessThan(100), "value is too large");
}
or
[Test]
public void ListContainsOneValue()
{
var list = GetListOf(1);
Assert.That(list, Is.Not.Null, "List is null");
Assert.That(list.Count, Is.EqualTo(1), "Should have one item in list");
Assert.That(list[0], Is.Not.Null, "Item is null");
}
You could combine these into one assert, but that's a different thing from insisting that you should or must. There is no improvement from combining them.
e.g. The first one could be
Assert.IsTrue((10 < value) && (value < 100), "Value out of range");
But this is not better - the error message out of it is less specific, and it has no other advantages. I'm sure you can think of other examples where combining two or three (or more) asserts into one big boolean condition makes it harder to read, harder to alter and harder to work out why it failed. Why do this just for the sake of a rule?
NB: The code that I am writing here is C# with NUnit, but the principles will hold with other languages and frameworks. The syntax may be very similar too.
RowTest
(MbUnit) /TestCase
(NUnit) to test a variety of edge-case behaviors. Use the proper tools for the job! (Unfortunately, MSTest doesn't seem to have a row-test capability yet.)RowTest
andTestCase
using test data sources. I'm using a simple CSV file with great success.