Xunit has a nice feature: you can create one test with a Theory
attribute and put data in InlineData
attributes, and xUnit will generate many tests, and test them all.
I want to have something like this, but the parameters to my method are not 'simple data' (like string
, int
, double
), but a list of my class:
public static void WriteReportsToMemoryStream(
IEnumerable<MyCustomClass> listReport,
MemoryStream ms,
StreamWriter writer) { ... }
There are many xxxxData
attributes in XUnit. Check out for example the PropertyData
attribute.
You can implement a property that returns IEnumerable<object[]>
. Each object[]
that this method generates will be then "unpacked" as a parameters for a single call to your [Theory]
method.
Another option is ClassData
, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.
See i.e. these examples from here:
PropertyData Example
public class StringTests2
{
[Theory, PropertyData(nameof(SplitCountData))]
public void SplitCount(string input, int expectedCount)
{
var actualCount = input.Split(' ').Count();
Assert.Equal(expectedCount, actualCount);
}
public static IEnumerable<object[]> SplitCountData
{
get
{
// Or this could read from a file. :)
return new[]
{
new object[] { "xUnit", 1 },
new object[] { "is fun", 2 },
new object[] { "to test with", 3 }
};
}
}
}
ClassData Example
public class StringTests3
{
[Theory, ClassData(typeof(IndexOfData))]
public void IndexOf(string input, char letter, int expected)
{
var actual = input.IndexOf(letter);
Assert.Equal(expected, actual);
}
}
public class IndexOfData : IEnumerable<object[]>
{
private readonly List<object[]> _data = new List<object[]>
{
new object[] { "hello world", 'w', 6 },
new object[] { "goodnight moon", 'w', -1 }
};
public IEnumerator<object[]> GetEnumerator()
{ return _data.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
}