在 xUnit.net 中的测试参量化类似于 NUnit

在 xUnit.net 框架中有没有类似于 NUnit 的以下特性的方法?

[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
}

这将在 NUnitGUI 中生成8个独立的测试

[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个独立的测试并自动比较结果(Assert.Equal())。

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

这将产生6个组合测试。无价。

几年前我尝试过 xUnit,并且很喜欢它,但是它缺少这些特性。不能没有他们。有什么变化吗?

61224 次浏览

XUnit 提供了一种通过 数据理论运行 参数化测试参数化测试的方法。这个概念与在 NUnit 中找到的相同,但是开箱即用的功能并不完整。

这里有一个例子:

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

在这个示例中,xUnit 将对每个 InlineDataAttribute运行一次 Should_format_the_currency_value_correctly测试,每次都将指定的值作为参数传递。

数据理论是一种 扩展点扩展点,您可以使用它来创建运行参数化测试的新方法。实现这一点的方法是通过 创造新的属性检查并可选地对测试方法的参数和返回值进行操作。

您可以找到一个很好的实例,说明如何将 xUnit 的数据理论扩展到 AutoFixture自动数据InlineAutoData理论中。

让我在这里再放一个样本,以防节省某人的时间。

[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);
}

在您的第一个请求中,您可以使用找到的 给你示例。

可以构造一个静态类,其中包含测试集合所需的数据

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 属性定义测试

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 组合式:

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

[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
}

我把这里的所有答案都考虑在内,并且额外利用了 XUnit 的 TheoryData<,>通用类型,为我的测试中的“ 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} ");
}

Three tests runs observed from test explorer for 'My First Test'


NB 使用 VS2017(15.3.3)、 C # 7和 XUnit 2.2.0 for. NET Core

根据 xUnit 中的 这篇文章,你有三个“参数化”选项:

  1. InlineData
  2. 类别资料
  3. MemberData

InlineData 示例

[Theory]
[InlineData(1, 2)]
[InlineData(-4, -6)]
[InlineData(2, 4)]
public void FooTest(int value1, int value2)
{
Assert.True(value1 + value2 < 7)
}

ClassData 示例

public class BarTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { 1, 2 };
yield return new object[] { -4, -6 };
yield return new object[] { 2, 4 };
}


IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}




[Theory]
[ClassData(typeof(BarTestData))]
public void BarTest(int value1, int value2)
{
Assert.True(value1 + value2 < 7)
}

MemberData 示例

[Theory]
[MemberData(nameof(BazTestData))]
public void BazTest(int value1, int value2)
{
Assert.True(value1 + value2 < 7)
}


public static IEnumerable<object[]> BazTestData => new List<object[]>
{
new object[] { 1, 2 },
new object[] { -4, -6 },
new object[] { 2, 4 },
};