C# – Parameterized tests with MSTest v2

There are two steps for parameterizing a unit test when using the MSTest v2 framework (built-in default):

  1. Add parameters to your test method.
  2. For each test case, add the [DataRow] attribute with the parameter values.

Here’s an example:

[DataRow(BirdType.Cardinal, 8.0, 9.0)]
[DataRow(BirdType.Goldfinch, 4.5, 5.5)]
[DataRow(BirdType.Chickadee, 4.75, 5.75)]
[DataTestMethod]
public void GetSizeRange(BirdType birdType, double expectedSizeRangeLower, double expectedSizeRangeUpper)
{
	//arrange
	var bird = Bird.Create(birdType);

	//act
	var actual = bird.GetSizeRange();

	//assert
	Assert.AreEqual(expectedSizeRangeLower, actual.Lower);
	Assert.AreEqual(expectedSizeRangeUpper, actual.Upper);
}
Code language: C# (cs)

Parameterized unit tests are useful because you only need one test method for multiple test cases instead of one test method per test case. It’s a simple way to declutter your unit tests and make them easier to maintain in the long run.

What parameters can you pass in?

You pass in parameters via the DataRow attribute. Since this is an attribute, it only accepts compile-time constants (primitives, arrays, enums).

Therefore you can’t pass in class instances. Instead, you can pass in parameters and use them to build the object in the test method.

For example, because I can’t pass in a BirdSizeRange object, I have to pass in the expectedSizeRangeLower and expectedSizeRangeUpper parameters. Then in the test I can construct the BirdSizeRange from these parameters.

public void GetSizeRange(BirdType birdType, double expectedSizeRangeLower, double expectedSizeRangeUpper)
{
	//arrange
	var bird = Bird.Create(birdType);
	BirdSizeRange expectedRange = new BirdSizeRange()
	{
		Upper = expectedSizeRangeLower,
		Lower = expectedSizeRangeUpper
	};

	//act
	var actual = bird.GetSizeRange();

	//assert
	Assert.AreEqual(expectedRange, actual);
}
Code language: C# (cs)

Note: In addition to using [DataRow], you can use [DynamicData] for supplying dynamic data for test cases (instead of hardcoding the data with [DataRow].