在类似于NUnit的xUnit.net中testing参数化

有没有类似于NUnit的以下function的xUnit.net框架中的任何手段?

[Test, TestCaseSource("CurrencySamples")] public void Format_Currency(decimal value, string expected){} static object[][] CurrencySamples = new object[][] { new object[]{ 0m, "0,00"}, new object[]{ 0.0004m, "0,00"}, new object[]{ 5m, "5,00"}, new object[]{ 5.1m, "5,10"}, new object[]{ 5.12m, "5,12"}, new object[]{ 5.1234m, "5,12"}, new object[]{ 5.1250m, "5,13"}, // round new object[]{ 5.1299m, "5,13"}, // round } 

这将在NUnit GUI中生成8个单独的testing

 [TestCase((string)null, Result = "1")] [TestCase("", Result = "1")] [TestCase(" ", Result = "1")] [TestCase("1", Result = "2")] [TestCase(" 1 ", Result = "2")] public string IncrementDocNumber(string lastNum) { return "some"; } 

这将生成5个独立的testing,并自动比较结果( Assert.Equal() )。

 [Test] public void StateTest( [Values(1, 10)] int input, [Values(State.Initial, State.Rejected, State.Stopped)] DocumentType docType ){} 

这将产生6个组合testing。 无价。

几年前,我尝试过xUnit并喜欢它,但缺乏这些function。 不能没有他们的生活。 有什么改变?

xUnit提供了一种通过数据理论运行参数化testing的方法。 这个概念与NUnit中的概念相同,但是你开箱即用的function并不完整。

这是一个例子:

 [Theory] [InlineData("Foo")] [InlineData(9)] [InlineData(true)] public void Should_be_assigned_different_values(object value) { Assert.NotNull(value); } 

在这个例子中,xUnit每次InlineDataAttribute为每个InlineDataAttribute运行一次Should_format_the_currency_value_correctlytesting,作为parameter passing指定的值。

数据理论是一个可扩展性点 ,您可以使用它来创build运行参数化testing的新方法。 这样做的方式是通过创build新的属性来检查和可选地对testing方法的参数和返回值进行操作。

你可以在AutoFixture的AutoData和InlineAutoData理论中find一个很好的实例来说明如何扩展xUnit的数据理论。

让我再在这里再举一个例子,以防万一给某人节省一些时间。

 [Theory] [InlineData("goodnight moon", "moon", true)] [InlineData("hello world", "hi", false)] public void Contains(string input, string sub, bool expected) { var actual = input.Contains(sub); Assert.Equal(expected, actual); } 

在你的第一个请求,你可以按照这里find的例子。

您可以构造一个包含testing集合所需数据的静态类

 using System.Collections.Generic; namespace PropertyDataDrivenTests { public static class DemoPropertyDataSource { private static readonly List<object[]> _data = new List<object[]> { new object[] {1, true}, new object[] {2, false}, new object[] {-1, false}, new object[] {0, false} }; public static IEnumerable<object[]> TestData { get { return _data; } } } } 

然后,使用MemberData属性,像这样定义testing

 public class TestFile1 { [Theory] [MemberData("TestData", MemberType = typeof(DemoPropertyDataSource))] public void SampleTest1(int number, bool expectedResult) { var sut = new CheckThisNumber(1); var result = sut.CheckIfEqual(number); Assert.Equal(result, expectedResult); } } 

或者如果您使用的是C#6.0,

 [Theory] [MemberData(nameof(PropertyDataDrivenTests.TestData), MemberType = typeof(DemoPropertyDataSource))] 

MemberDataAttribute的第一个参数允许您定义用作数据源的成员,因此在重用时有相当大的灵活性。

我发现一个库产生与NUnit的[Values] Xunit.Combinatorial [Values]属性相同的function:

它允许您指定参数级别的值:

 [Theory, CombinatorialData] public void CheckValidAge([CombinatorialValues(5, 18, 21, 25)] int age, bool friendlyOfficer) { // This will run with all combinations: // 5 true // 18 true // 21 true // 25 true // 5 false // 18 false // 21 false // 25 false } 

或者你可以隐含地指出调用的最小数量来覆盖所有可能的组合:

 [Theory, PairwiseData] public void CheckValidAge(bool p1, bool p2, bool p3) { // Pairwise generates these 4 test cases: // false false false // false true true // true false true // true true false } 

我在这里把所有的答案都写在这里,另外还使用了TheoryData<,>TheoryData<,>genericstypes,以便为我的testing中的'MemberData'属性提供简单,易读和安全的数据定义,如下例所示:

 /// must be public & static for MemberDataAttr to use public static TheoryData<int, bool, string> DataForTest1 = new TheoryData<int, bool, string> { { 1, true, "First" }, { 2, false, "Second" }, { 3, true, "Third" } }; [Theory(DisplayName = "My First Test"), MemberData(nameof(DataForTest1))] public void Test1(int valA, bool valB, string valC) { Debug.WriteLine($"Running {nameof(Test1)} with values: {valA}, {valB} & {valC} "); } 

从测试资源管理器观察到三个测试运行“我的第一个测试”


NB使用VS2017(15.3.3),C#7和用于.NET Core的XUnit 2.2.0