NUnit TestCaseData

时间:2016-08-16 08:34:17

标签: c# unit-testing nunit

我试图为我的测试设置一些测试用例:

public IEnumerable<TestCaseData> size_tests()
{
    yield return new TestCaseData(new string[] { "XS", "XL", "M" })
        .Returns(new SortedVariantAttributeModel {
            Values = new string[] { "XS", "M", "XL" },
            PrimaryValue = "XS"
        });
}

[Test, TestCaseSource("size_tests")]
public SortedVariantAttributeModel Should_map_SortedVariantAttributes(string[] sizes)
{
    // ...
}

当我尝试运行此测试时,我得到:

  

测试失败 - Should_map_SortedVariantAttributes(&#34; XS&#34;,&#34; XL&#34;,&#34; M&#34;)

     

消息:提供的参数数量错误

判断错误似乎解开数组并尝试将其应用于测试函数,但这当然会导致问题。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

要使其正常工作,您需要将参数包装在这样的数组new[] { new string[] { "XS", "XL", "M" } }中。这会导致NUnit将字符串数组视为方法的第一个参数,而不是一系列字符串参数。

我相信您使用的是NUnit 2.x,因为您的数据源不是静态的。我简化了您的代码并测试了NUnit 2.6.4和3.4.1中的变通方法。

public static IEnumerable<TestCaseData> Data()
{
    yield return new TestCaseData(new[] { new string[] { "XS", "XL", "M" } });
    yield return new TestCaseData(new[] { new string[] { "S", "M", "XXL", "L" } });
}

[TestCaseSource(nameof(Data))]
public void TestStringArrayArguments(string[] sizes)
{
    Assert.That(sizes.Length, Is.GreaterThan(1));
}

答案 1 :(得分:2)

相关的实例构造函数具有以下重载:

public TestCaseData(params object[] args) { /* ... */ } //A

public TestCaseData(object arg) { /* ... */ } //B

public TestCaseData(object arg1, object arg2) { /* ... */ } //C

public TestCaseData(object arg1, object arg2, object arg3) { /* ... */ } //D

params的重载可以通过两种方式应用,可以是普通形式,您可以在代码中明确地提供对象数组,也可以扩展形式您只需用逗号指定一堆对象(零或多个),编译器就会隐式生成数组。请参阅C#规范中的§7.5.3.1适用的函数成员

当你这样做时:

new TestCaseData(new string[] { "XS", "XL", "M" })

对于引用类型数组(string是引用类型),C#(以及CLR)具有可疑的数组协方差变得很重要。因此,string[]“也是object[](使用stringobject的协方差。)

所以重载//A适用于普通形式。如果适用普通表格,则不应考虑扩展形式的//A

您的使用中的重载//B也适用,因为string[]System.Arrayobject

但是//A被认为更具体(所有object[]都是object但现在反之亦然)并且优先于//B。因此,//A以正常形式使用 ,这不是您想要的。您的Should_map_SortedVariantAttributes需要一个参数(称为sizes),而不是三个。因此问题。

现在很容易找到一个好的解决方案:

new TestCaseData((object)(new string[] { "XS", "XL", "M" })) /* fixes your issue! */

现在我们有一个object类型的表达式。重载//A不再适用于其正常形式。所以这一次检查//A是否适用于它的扩展形式。

//B也适用于此。

其展开形式的//A //B会使您的代码正常工作,因此无论C#重载决策在这种情况下选择了什么,我们都很高兴。< / p>

实际上,在这种情况下,C#规则(第7.5.3.2节)更喜欢通常的形式而非扩展形式,因此使用//B。这是一件好事,编译器不必创建隐式的长度为1的对象数组。