How do you write a parameterized (data-driven) test?

Unit Testing & TDD Frameworks Basic 1–2 Yrs2–3 Yrs Coding 1 min read

Quick Answer

In xUnit, use [Theory] with [InlineData(...)] for simple constant cases or [MemberData(nameof(Cases))] / [ClassData] for complex ones. NUnit uses [TestCase(...)] or [TestCaseSource]. One test method runs once per data row, and each row shows as a separate result.

In xUnit I mark the method [Theory] instead of [Fact] and add [InlineData] attributes, one per set of inputs, so I can test a dozen boundary cases — zero, negative, max, null — with one method and one assertion. If the inputs are objects or I need to build them, I use [MemberData] pointing at a static property that returns the rows. NUnit's equivalent is [TestCase]. The framework reports each row as its own test, so a failure tells me exactly which input broke.

  • Great for boundary testing — one method, rows for min, max, zero, negative, null.
  • [MemberData] source is a static IEnumerable<object[]> property/method — use it when the inputs are objects or need computing.
  • Keep the assertion generic across all rows; if one row needs a different assertion, it's a different test.

C# — xUnit Theory
[Theory]
[InlineData(0, false)]
[InlineData(17, false)]
[InlineData(18, true)]
[InlineData(65, true)]
public void IsAdult_ReturnsExpected(int age, bool expected)
{
    var result = AgeChecker.IsAdult(age);
    Assert.Equal(expected, result);
}