C# 与NUnit类似的xUnit.net中的测试参数化

C# 与NUnit类似的xUnit.net中的测试参数化,c#,.net,unit-testing,nunit,xunit.net,C#,.net,Unit Testing,Nunit,Xunit.net,在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

在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()

这将生成6个组合测试。无价之宝

几年前,我试过xUnit并喜欢它,但它缺少这些功能。没有他们,我无法生活。有什么变化吗?

提供了一种通过数据理论运行参数化测试的方法。这个概念相当于NUnit中的概念,但您从盒子中获得的功能并不完整

下面是一个例子:

[Theory]
[InlineData("Foo")]
[InlineData(9)]
[InlineData(true)]
public void Should_be_assigned_different_values(object value)
{
    Assert.NotNull(value);
}
在本例中,每次将指定值作为参数传递时,xUnit将为每个
InlineDataAttribute
正确地运行
Should\u format\u\u\u货币\u值
测试一次

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


你可以找到一个很好的实例,说明xUnit的数据理论如何在’s和’s理论中得到扩展。

让我在这里再举一个例子,以防它能为某人节省一些时间

[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; }
        }
    }
}
或者如果您使用的是C#6.0


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

我发现一个库,它可以生成与NUnit的
[Values]
属性等效的功能,名为:

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

[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} ");
}
///必须是公共的和静态的,MemberDataAttr才能使用
公共静态TheoryData DataForTest1=新TheoryData{
{1,对,“第一”},
{2,false,“Second”},
{3,对,“第三”}
};
[理论(DisplayName=“我的第一次测试”),成员数据(nameof(DataForTest1))]
公共void Test1(int valA、bool valB、string valC)
{
WriteLine($“正在运行{nameof(Test1)},值为:{valA},{valB}&{valC}”);
}


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

根据XUnit,您有三个“参数化”选项:

  • 内联数据
  • 类数据
  • 成员数据
  • 内联数据示例

    [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 },
        };
    
    [理论]
    [在线数据(1,2)]
    [在线数据(-4,-6)]
    [在线数据(2,4)]
    公共空间英尺(整数值1、整数值2)
    {
    Assert.True(value1+value2<7)
    }
    
    类数据示例

    [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 },
        };
    
    公共类易货数据:IEnumerable
    {
    公共IEnumerator GetEnumerator()
    {
    返回新对象[]{1,2};
    返回新对象[]{-4,-6};
    产生返回新对象[]{2,4};
    }
    IEnumerator IEnumerable.GetEnumerator()=>GetEnumerator();
    }
    [理论]
    [ClassData(typeof(BarTestData))]
    公共无效易货交易(内部价值1,内部价值2)
    {
    Assert.True(value1+value2<7)
    }
    
    成员数据示例

    [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 },
        };
    
    [理论]
    [成员数据(名称(BazTestData))]
    公共测试(int值1、int值2)
    {
    Assert.True(value1+value2<7)
    }
    公共静态IEnumerable BazTestData=>新列表
    {
    新对象[]{1,2},
    新对象[]{-4,-6},
    新对象[]{2,4},
    };
    
    显然,这是使用十进制文字作为属性参数。@rubenbarterlink找不到您的链接。改为转到这里:您将需要xUnit.net:Extensions(NuGet包)或
    [理论]
    属性不可用。如果最推荐的.NET单元测试框架有一些文档就好了。谷歌说你的答案是xUnit文档。这很好。这是一个完整的指南,可以将复杂对象作为参数发送到测试方法