将复杂参数传递给 [Theory] [英] Pass complex parameters to [Theory]

查看:29
本文介绍了将复杂参数传递给 [Theory]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Xunit 有一个不错的功能:你可以创建一个带有 Theory 属性的测试并将数据放在 InlineData 属性中,xUnit 将生成许多测试,并测试它们.

我想要这样的东西,但我的方法的参数不是简单数据"(如stringintdouble>),但我的班级名单:

public static void WriteReportsToMemoryStream(IEnumerable清单报告,内存流毫秒,StreamWriter 作家) { ... }

解决方案

XUnit 中有很多 xxxxData 属性.例如,查看 MemberData 属性.

您可以实现返回 IEnumerable 的属性.此方法生成的每个 object[] 然后将被解包".作为对 [Theory] 方法的单个调用的参数.

参见 ie 此处的这些示例

以下是一些示例,仅供快速浏览.

MemberData 示例:就在身边

公共类 StringTests2{[理论,MemberData(nameof(SplitCountData))]public void SplitCount(字符串输入,int expectedCount){var actualCount = input.Split(' ').Count();Assert.Equal(expectedCount, actualCount);}公共静态 IEnumerableSplitCountData =>新列表{新对象[] {xUnit",1},新对象[] {很有趣",2},new object[] { 测试对象", 3 }};}

XUnit <2.0:另一个选项是 ClassData,它的工作原理相同,但允许在不同类/命名空间中的测试之间轻松共享生成器",并将数据生成器"与实际测试方法分开.

类数据示例

公共类 StringTests3{[理论,ClassData(typeof(IndexOfData))]public void IndexOf(string input, char letter, int expected){var 实际 = input.IndexOf(letter);Assert.Equal(预期,实际);}}公共类 IndexOfData : IEnumerable{私有只读列表_data = 新列表{new object[] { "hello world", 'w', 6 },新对象[] {晚安月亮",w",-1}};公共 IEnumerator获取枚举器(){返回_data.GetEnumerator();}IEnumerator IEnumerable.GetEnumerator(){ 返回 GetEnumerator();}}

XUnit >= 2.0:代替 ClassData,现在有一个 [MemberData] 的重载",允许使用来自其他类的静态成员.下面的示例已更新以使用它,因为 XUnit <;2.x 现在已经很古老了.另一个选项是 ClassData,它的工作原理相同,但允许在不同类/命名空间中的测试之间轻松共享生成器",并将数据生成器"与实际测试方法分开.>

MemberData 示例:寻找另一种类型

公共类 StringTests3{[理论,MemberData(nameof(IndexOfData.SplitCountData),MemberType = typeof(IndexOfData))]public void IndexOf(string input, char letter, int expected){var 实际 = input.IndexOf(letter);Assert.Equal(预期,实际);}}公共类 IndexOfData : IEnumerable{公共静态 IEnumerableSplitCountData =>新列表{new object[] { "hello world", 'w', 6 },新对象[] {晚安月亮",w",-1}};}

免责声明:)

上次在 C# 5.0 和 xunit 2.4.1 上使用 dotnetfiddle.net 检查 @20210903 .. 并失败.我无法在那个小提琴中混入一个测试运行器.但至少它编译得很好.请注意,这最初是几年前写的,事情发生了一些变化.我根据我的预感和评论修复了它们.所以..它可能包含不明显的错别字,否则会在运行时立即弹出的明显错误,以及牛奶和牛奶的痕迹.坚果.

Xunit has a nice feature: you can create one test with a Theory attribute and put data in InlineData attributes, and xUnit will generate many tests, and test them all.

I want to have something like this, but the parameters to my method are not 'simple data' (like string, int, double), but a list of my class:

public static void WriteReportsToMemoryStream(
    IEnumerable<MyCustomClass> listReport,
    MemoryStream ms,
    StreamWriter writer) { ... }

解决方案

There are many xxxxData attributes in XUnit. Check out for example the MemberData attribute.

You can implement a property that returns IEnumerable<object[]>. Each object[] that this method generates will be then "unpacked" as a parameters for a single call to your [Theory] method.

See i.e. these examples from here

Here are some examples, just for a quick glance.

MemberData Example: just here at hand

public class StringTests2
{
    [Theory, MemberData(nameof(SplitCountData))]
    public void SplitCount(string input, int expectedCount)
    {
        var actualCount = input.Split(' ').Count();
        Assert.Equal(expectedCount, actualCount);
    }
 
    public static IEnumerable<object[]> SplitCountData => 
        new List<object[]>
        {
            new object[] { "xUnit", 1 },
            new object[] { "is fun", 2 },
            new object[] { "to test with", 3 }
        };
}

XUnit < 2.0: Another option is ClassData, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.

ClassData Example

public class StringTests3
{
    [Theory, ClassData(typeof(IndexOfData))]
    public void IndexOf(string input, char letter, int expected)
    {
        var actual = input.IndexOf(letter);
        Assert.Equal(expected, actual);
    }
}
 
public class IndexOfData : IEnumerable<object[]>
{
    private readonly List<object[]> _data = new List<object[]>
    {
        new object[] { "hello world", 'w', 6 },
        new object[] { "goodnight moon", 'w', -1 }
    };
 
    public IEnumerator<object[]> GetEnumerator()
    { return _data.GetEnumerator(); }
 
    IEnumerator IEnumerable.GetEnumerator()
    { return GetEnumerator(); }
}

XUnit >= 2.0: Instead of ClassData, now there's an 'overload' of [MemberData] that allows to use static members from other classes. Examples below have been updated to use it, since XUnit < 2.x is pretty ancient now. Another option is ClassData, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.

MemberData Example: look there to another type

public class StringTests3
{
    [Theory, MemberData(nameof(IndexOfData.SplitCountData), MemberType = typeof(IndexOfData))]
    public void IndexOf(string input, char letter, int expected)
    {
        var actual = input.IndexOf(letter);
        Assert.Equal(expected, actual);
    }
}
 
public class IndexOfData : IEnumerable<object[]>
{
    public static IEnumerable<object[]> SplitCountData => 
        new List<object[]>
        {
            new object[] { "hello world", 'w', 6 },
            new object[] { "goodnight moon", 'w', -1 }
        };
}

Disclaimer :)

Last time checked @20210903 with dotnetfiddle.net on C# 5.0 and xunit 2.4.1 .. and failed. I couldn't mix-in a test-runner into that fiddle. But at least it compiled fine. Note that this was originally written years ago, things changed a little. I fixed them according to my hunch and comments. So.. it may contain inobvious typos, otherwise obvious bugs that would instantly pop up at runtime, and traces of milk & nuts.

这篇关于将复杂参数传递给 [Theory]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆