Parametrized Tests
Running tests with different data is a nice feature. MsTest is pretty poor here, XUnit is ok, and NUnit has very rich, flexible support.
MsTest
It's called data driven tests in Visual Studio, and needs a Sql database (ugh) or a CSV or XML file source. Tests can't have arguments- you access an instance TestContext (not the static version).
Add an xml file, with Copy to Output Directory=Always
<Products>
<!-- Copy to Output Directory=Always-->
<Product>
<Name>Apple</Name>
<Price>10</Price>
</Product>
<Product>
<Name>Orange</Name>
<Price>12</Price>
</Product>
</Products>
The test has a DataSource attribute.
//it does property injection into this
public TestContext TestContext { get; set; }
[TestMethod,
DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
"XmlData.xml", // file name
"Product", // root/element
DataAccessMethod.Sequential
)]
public void TestDataDriven()
{
var name = TestContext.DataRow["Name"].ToString();
var price = Int32.Parse(TestContext.DataRow["Price"].ToString());
}
NUnit
There are three types of parametrized tests - simple inline tests, using properties and/or helper classes, and theories.
This is inline:
//inline parameters
[Test, Sequential]
public void TestMethod1(
[Values("A", "ABC")] string value,
[Values(1, 3)] int expected)
{
Assert.AreEqual(expected, value.Length);
}
[Test] //implicitly [Combinatorial]
public void TestMethod2(
[Values("A", "ABC")] string value,
[Values(1, 3)] int expected)
{
//gets A + 1, A + 3, ABC + 1, ABC + 3
}
You can pull from a method or property (and specify another class)
//pull from a IEnumerable member (maybe in another class)
[Test, TestCaseSource("GetData")]
public void TestMethod3(Product product)
{
Console.WriteLine(product.Name);
}
//or return IEnumerable and yield return new TestCaseData(1, 2);
public IEnumerable<Product> GetData
{
get
{
yield return new Product("Apple", 10);
yield return new Product("Orange", 12);
}
}
Theories are similar. Instead of [Test] you have [Theory] and it looks up fields or properties by type with the [Datapoints] attribute.
//enums and bools are automatically generated; others from Datapoint[s] fields
[Theory]
public void TestMethod4(int i, DayOfWeek dayOfWeek) { }
[Datapoints]
private int[] _data = new[] { 1, 2, 3 };
XUnit
In XUnit, all parameter tests are [Theory], not [Fact]. In v1 you have to reference xunit.extensions.dll; in v2 it's built in.
[InlineData] is just like NUnit's [Values] attribute, but clearer as it's on the method with sequential mode.
[Theory]
[InlineData("A", 1)]
[InlineData("ABC", 3)]
public void TestInline(string value, int expected)
{
Assert.Equal(expected, value.Length);
}
In v1 you could also refer to a public static property with [PropertyData("GetData")]. In v2, it can be a public static property or method via [MemberData("GetData")].
[Theory]
[MemberData("GetData")]
public void TestMember(string value, int expected)
{
Assert.Equal(expected, value.Length);
}
public static IEnumerable<object[]> GetData
{
get
{
yield return new object[] { "A", 1 };
yield return new object[] { "ABC", 3 };
}
}