While doing a code review, I discovered a feature in XUnit I didn't know it existed. Let me share what I discovered.
I've been used to specify data for my parameterised tests either using the [InlineData]
attribute or through the [MemberData]
or [ClassData]
attributes.
When using [MemberData]
or [ClassData]
, XUnit expects that you return an IEnumerable<object[]> as far I as I know.
Here is an example:
public class CalculatorTests | |
{ | |
[Theory] | |
[MemberData(nameof(TestData))] | |
public void CanAdd(int value1, int value2, int expected) | |
{ | |
var calculator = new Calculator(); | |
var result = calculator.Add(value1, value2); | |
Assert.Equal(expected, result); | |
} | |
public static IEnumerable<object[]> TestData => | |
new List<object[]> | |
{ | |
new object[] { 1, 2, 3 }, | |
new object[] { -1, -2, -3 } | |
}; | |
} |
If I try to use a typed alternative, it results in a compiler error:
However it turns out that there is a type safe alternative available through TheoryData<>
.
The TheoryData<>
types provide a series of abstractions around the IEnumerable<object[]>
required by theory tests. It consists of a TheoryData
base class, and a number of generic derived classes TheoryData<>
. It can be used in combination with both the [MemberData]
or [ClassData]
attributes while enforcing type safety.
Here is our original example rewritten to use TheoryData<>
:
public class CalculatorTests | |
{ | |
[Theory] | |
[MemberData(nameof(TestData))] | |
public void CanAdd(int value1, int value2, int expected) | |
{ | |
var calculator = new Calculator(); | |
var result = calculator.Add(value1, value2); | |
Assert.Equal(expected, result); | |
} | |
public static TheoryData<int, int, int> TestData => | |
new TheoryData<int, int, int> | |
{ | |
{ 1, 2, 3 }, | |
{ -1, -2, -3 } | |
}; | |
} |
Nice!