Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MemberData测试显示为一个测试,而不是多个测试_C#_Xunit.net_Data Driven Tests_Xunit2 - Fatal编程技术网

C# MemberData测试显示为一个测试,而不是多个测试

C# MemberData测试显示为一个测试,而不是多个测试,c#,xunit.net,data-driven-tests,xunit2,C#,Xunit.net,Data Driven Tests,Xunit2,当您将[Theory]与[InlineData]一起使用时,它将为提供的每项内联数据创建一个测试。但是,如果使用[MemberData],它将只显示为一个测试 有没有办法让[MemberData]测试显示为多个测试?我在项目中花了很多时间试图解决这个问题。来自@NPadrutt的帮助很大,但仍然令人困惑 tl;dr是这样的:[MemberInfo]将报告单个组测试,除非通过实现IXunitSerializable可以完全序列化和反序列化每个测试提供的对象 背景 我自己的测试设置类似于: pub

当您将
[Theory]
[InlineData]
一起使用时,它将为提供的每项内联数据创建一个测试。但是,如果使用
[MemberData]
,它将只显示为一个测试


有没有办法让
[MemberData]
测试显示为多个测试?

我在项目中花了很多时间试图解决这个问题。来自@NPadrutt的帮助很大,但仍然令人困惑

tl;dr是这样的:
[MemberInfo]
将报告单个组测试,除非通过实现
IXunitSerializable
可以完全序列化和反序列化每个测试提供的对象


背景

我自己的测试设置类似于:

public static IEnumerable<object[]> GetClients()
{
    yield return new object[] { new Impl.Client("clientType1") };
    yield return new object[] { new Impl.Client("clientType2") };
}

[Theory]
[MemberData(nameof(GetClients))]
public void ClientTheory(Impl.Client testClient)
{
    // ... test here
}
测试

public static IEnumerable<object[]> GetClients()
{
    yield return new object[] { new TestClientBuilder("clientType1") };
    yield return new object[] { new TestClientBuilder("clientType2") };
}

[Theory]
[MemberData(nameof(GetClients))]
private void ClientTheory(TestClientBuilder clientBuilder)
{
    var client = clientBuilder.Build();
    // ... test here
}
public静态IEnumerable GetClients()
{
返回新对象[]{newtestclientbuilder(“clientType1”)};
返回新对象[]{newtestclientbuilder(“clientType2”)};
}
[理论]
[MemberData(nameof(GetClient))]
私有void客户端理论(TestClientBuilder客户端生成器)
{
var client=clientBuilder.Build();
//…在这里测试
}

我再也没有注入目标对象了,这有点恼人,但这只是调用我的构建器的一行额外代码。而且,我的测试通过了(并且出现了两次!),所以我没有抱怨。

MemberData可以使用返回对象[]的IEnumerable的属性或方法。 在此场景中,您将看到每个产量的单独测试结果:

public class Tests
{ 
    [Theory]
    [MemberData("TestCases", MemberType = typeof(TestDataProvider))]
    public void IsLargerTest(string testName, int a, int b)
    {
        Assert.True(b>a);
    }
}

public class TestDataProvider
{
    public static IEnumerable<object[]> TestCases()
    {
        yield return new object[] {"case1", 1, 2};
        yield return new object[] {"case2", 2, 3};
        yield return new object[] {"case3", 3, 4};
    }
}
公共类测试
{ 
[理论]
[MemberData(“TestCases”,MemberType=typeof(TestDataProvider))]
public void IsLargerTest(字符串testName,int a,int b)
{
断言为真(b>a);
}
}
公共类TestDataProvider
{
公共静态IEnumerable测试用例()
{
产生返回新对象[]{“case1”,1,2};
产生返回新对象[]{“case2”,2,3};
产生返回新对象[]{“case3”,3,4};
}
}
然而,只要您需要通过复杂的自定义对象,不管您将有多少个测试用例,测试输出窗口将只显示一个测试。 这不是理想的行为,在调试哪个测试用例失败时确实非常不方便。 解决方法是创建您自己的包装器,它将派生自IXunitSerializable

public class MemberDataSerializer<T> : IXunitSerializable
    {
        public T Object { get; private set; }

        public MemberDataSerializer()
        {
        }

        public MemberDataSerializer(T objectToSerialize)
        {
            Object = objectToSerialize;
        }

        public void Deserialize(IXunitSerializationInfo info)
        {
            Object = JsonConvert.DeserializeObject<T>(info.GetValue<string>("objValue"));
        }

        public void Serialize(IXunitSerializationInfo info)
        {
            var json = JsonConvert.SerializeObject(Object);
            info.AddValue("objValue", json);
        }
    }
公共类MemberDataSerializer:IXunitSerializable { 公共T对象{get;私有集;} 公共成员数据序列化程序() { } 公共成员数据序列化程序(T objectToSerialize) { 对象=对象序列化; } public void反序列化(IXunitSerializationInfo) { Object=JsonConvert.DeserializeObject(info.GetValue(“objValue”); } 公共void序列化(IXunitSerializationInfo) { var json=JsonConvert.SerializeObject(对象); info.AddValue(“objValue”,json); } } 现在,您可以将自定义对象作为Xunit理论的参数,并且仍然可以在test runner窗口中作为独立结果查看/调试它们:

public class UnitTest1
{
    [Theory]
    [MemberData("TestData", MemberType = typeof(TestDataProvider))]
    public void Test1(string testName, MemberDataSerializer<TestData> testCase)
    {
        Assert.Equal(1, testCase.Object.IntProp);
    }
}

public class TestDataProvider
{
    public static IEnumerable<object[]> TestData()
    {
        yield return new object[] { "test1", new MemberDataSerializer<TestData>(new TestData { IntProp = 1, StringProp = "hello" }) };
        yield return new object[] { "test2", new MemberDataSerializer<TestData>(new TestData { IntProp = 2, StringProp = "Myro" }) };      
    }
}

public class TestData
{
    public int IntProp { get; set; }
    public string StringProp { get; set; }
}
公共类UnitTest1
{
[理论]
[MemberData(“TestData”,MemberType=typeof(TestDataProvider))]
public void Test1(字符串testName,MemberDataSerializer testCase)
{
等于(1,testCase.Object.IntProp);
}
}
公共类TestDataProvider
{
公共静态IEnumerable TestData()
{
产生返回新对象[]{“test1”,新成员数据序列化器(新的TestData{IntProp=1,StringProp=“hello”});
产生返回新对象[]{“test2”,新成员数据序列化器(新TestData{IntProp=2,StringProp=“Myro”});
}
}
公共类测试数据
{
公共int IntProp{get;set;}
公共字符串StringProp{get;set;}
}

希望这能有所帮助。

在我最近的项目中,我遇到了同样的问题,经过一些研究,我提出的解决方案如下:

实现自定义MyTheoryAttribute扩展FactAttribute,以及MyTheoryDiscoveryr实现IXUnitTestCaseDiscoveryr和几个自定义MyTestCases扩展TestMethodTestCase并实现IXunitTestCase以满足您的需要。您的自定义测试用例应该由MyTheoryDiscoveryr识别,并用于以Xunit框架可见的形式封装您的枚举理论测试用例,即使传递的值不是Xunit本机序列化的,也不实现IXunitSerializable

public class MemberDataSerializer<T> : IXunitSerializable
    {
        public T Object { get; private set; }

        public MemberDataSerializer()
        {
        }

        public MemberDataSerializer(T objectToSerialize)
        {
            Object = objectToSerialize;
        }

        public void Deserialize(IXunitSerializationInfo info)
        {
            Object = JsonConvert.DeserializeObject<T>(info.GetValue<string>("objValue"));
        }

        public void Serialize(IXunitSerializationInfo info)
        {
            var json = JsonConvert.SerializeObject(Object);
            info.AddValue("objValue", json);
        }
    }
最重要的是无需更改您宝贵的测试代码

这是一个有点工作要做,但因为它已经由我做了,并根据麻省理工学院许可证提供,请随意使用它。它是托管在GitHub上的项目的一部分

使用Xunit支持代码直接链接到相关文件夹如下:

若要使用它,请使用此文件创建单独的程序集,或将它们直接包含到测试项目中

用法与Xunit TheoryAttribute完全相同,同时支持ClassDataAttribute和MemberDataAttribute,即:

[DjvuTheory]
[ClassData(typeof(DjvuJsonDataSource))]
public void InfoChunk_Theory(DjvuJsonDocument doc, int index)
{
    // Test code goes here
}


[DjvuTheory]
[MemberData(nameof(BG44TestData))]
public void ProgressiveDecodeBackground_Theory(BG44DataJson data, long length)
{
    // Test code goes here
}

另一个开发人员也有功劳,但不幸的是,我现在无法在github上找到他的repo。当您的自定义类重写
ToString()
时,ReSharper可以使用自定义参数显示所有MemberData测试

例如:

公共静态TheoryData GetAddRuleData()
{
var数据=新的TheoryData
{
{
新权限(“book”,new[]{“read”},null),
新权限(“book”,new[]{“delete”},new[]{“2333”}),
新权限(“book”,新[]{“delete”,“read”},新[]{“*”,“2333”})
},
{
新权限(“book”,new[]{“read”},null),
新权限(“音乐”,新[]{“阅读”},新[]{“2333”}),新权限
{
参考资料=新字典