在 xUnit.net 中测试参数化,类似于 NUnit

问题描述 投票:0回答:6

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
}

这将在 NUnit GUI 中生成 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 并且很喜欢它,但它缺乏这些功能。没有他们就活不下去。有什么变化吗?

c# .net unit-testing nunit xunit.net
6个回答
169
投票

xUnit 提供了一种通过称为“数据理论”的东西来运行“参数化测试”的方法。这一概念与 NUnit 中的概念等效,但开箱即用的功能并不完整。 这是一个例子: [Theory] [InlineData("Foo")] [InlineData(9)] [InlineData(true)] public void Should_be_assigned_different_values(object value) { Assert.NotNull(value); }

在此示例中,每次将指定值作为参数传递时,xUnit 将为每个

Should_be_assigned_different_values
 运行一次 
InlineDataAttribute

测试。

数据理论是一个
可扩展点
,您可以使用它来创建运行参数化测试的新方法。完成此操作的方法是通过

创建新属性

来检查并选择性地对测试方法的参数和返回值进行操作。 您可以在 AutoFixture

AutoData

InlineAutoData 理论中找到关于如何扩展 xUnit 数据理论的一个很好的实际示例。 让我在这里再扔一个示例,以防万一它可以为某人节省一些时间。


68
投票

根据
这篇文章

28
投票

内联数据

类数据
  1. 会员资料
  2. InlineData 示例

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

类数据示例


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

会员数据示例


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

在您第一次请求时,您可以按照
此处

27
投票

您可以构造一个静态类,其中包含测试集合所需的数据 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]

15
投票
Xunit.Combinatorial

:


它允许您指定参数级别值: [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<,>

14
投票

/// 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 和 XUnit 2.2.0 for .NET Core


© www.soinside.com 2019 - 2024. All rights reserved.