Automating Tests
With data driven tests you write out every test case yourself. NUnit can also do that work for you: you describe the possible values for each parameter, and NUnit generates the test cases. This is a good way to cover many inputs with very little code.
Every combination with [Values]
Put [Values] on each parameter. By default NUnit runs the test once for every combination
of the values, so the example below produces 3 × 2 = 6 test cases.
public class AddIsCommutativeTests
{
[Test]
public void Add_IsCommutative([Values(-1, 0, 1)] int a, [Values(2, 3)] int b)
{
var calculator = new Calculator();
Assert.That(calculator.Add(a, b), Is.EqualTo(calculator.Add(b, a)));
}
}
For bool and enum parameters you can leave out the values: [Values] bool flag gives you both true and
false.
A range of numbers with [Range]
Use [Range] to generate numbers from a start value to an end value, with an optional step.
This example runs with -10, -5, 0, 5 and 10.
public class AddZeroTests
{
[Test]
public void Add_Zero_ReturnsSameNumber([Range(-10, 10, 5)] int number)
{
Assert.That(new Calculator().Add(number, 0), Is.EqualTo(number));
}
}
Random numbers with [Random]
Use [Random] to have NUnit pick values for you. This is useful for checking rules that must
hold for any input, such as a + b == b + a. NUnit records the random seed it used in the test results, so a failing run can be reproduced.
public class AddRandomTests
{
[Test]
public void Add_IsCommutative_ForRandomNumbers(
[Random(-1000, 1000, 5)] int a,
[Random(-1000, 1000, 5)] int b)
{
var calculator = new Calculator();
Assert.That(calculator.Add(a, b), Is.EqualTo(calculator.Add(b, a)));
}
}
To create random values in the test code itself, use the Randomizer from
TestContext.CurrentContext.Random. It uses the same seed, so these values can be reproduced too.
Keeping the number of tests down
Combinations grow fast: three parameters with ten values each give a thousand test cases. NUnit has two attributes that change how the values are combined:
[Pairwise]generates just enough cases so that every pair of values is tested together at least once. Most bugs are caused by one value or by two values together, so this finds most of them with far fewer tests.[Sequential]uses the first value of each parameter together, then the second values, and so on, instead of all combinations.
public class FormattingTests
{
[Test, Pairwise]
public void Format_HandlesAllOptions(
[Values("en-US", "nb-NO", "ja-JP")] string culture,
[Values(0, 1, -1)] int number,
[Values(true, false)] bool useGrouping)
{
var format = useGrouping ? "N0" : "D";
var text = number.ToString(format, new System.Globalization.CultureInfo(culture));
Assert.That(text, Is.Not.Empty);
}
}
Theories
A [Theory] goes one step further: you state something that must be true for all data
points, and NUnit tries it with every suitable value you have marked with [Datapoint]
or [DatapointSource].
Next steps
- Combinatorial, Pairwise and Sequential describe the combining strategies in detail.
- Parameterized tests describes all the details of how parameterized tests work.