Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong number of arguments with NUnit TestCaseData

I'm trying to set up some test cases for my test:

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)
{
    // ...
}

When I try to run this test, I get:

Test Failed - Should_map_SortedVariantAttributes("XS","XL","M")

Message: Wrong number of arguments provided

Judging by the error it seems to unwrap the array and try to apply it to the test function, but that results in problems of course. How do I solve this?

like image 430
Bart van den Burg Avatar asked Oct 18 '25 04:10

Bart van den Burg


2 Answers

To get this working, you need to wrap the arguments in an array like this, new[] { new string[] { "XS", "XL", "M" } }. This causes NUnit to treat the string array as the first argument to a method instead of a series of string arguments.

I believe that you are using NUnit 2.x because your data source is not static. I simplified your code and tested the workaround in NUnit 2.6.4 and 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));
}
like image 117
Rob Prouse Avatar answered Oct 20 '25 18:10

Rob Prouse


The relevant instance constructor has the following overloads:

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

The overload with params can apply in two ways, either in the normal form where you give the object array explicitly in your code, or in the expanded form where you just specify a bunch of objects (zero or more) with commas and the compiler produces the array for you implicitly. See §7.5.3.1 Applicable function member in the C# spec.

When you do:

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

it becomes important that C# (as well as the CLR) has a dubious array covariance for arrays of reference types (string is a reference type). So your string[] "is" also an object[] (use covariance on the fact that a string is an object).

So overload //A applies in normal form. When normal form applies, //A in expanded form shall not be considered.

Overload //B in your use is also applicable, since a string[] is a System.Array which is an object.

However //A is considered more specific (all object[] are object but now vice versa) and is preferred over //B. So //A is used in its normal form which is not what you want. Your Should_map_SortedVariantAttributes takes one argument (called sizes), not three. Hence the problem.

A good solution is now easy:

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

Now we have an expression of type object. The overload //A is not applicable in its normal form anymore. So this time it is checked if //A is applicable in its expanded form, which it is.

Also //B is applicable here.

Either //A in its expanded form or //B would make your code work, so no matter what the C# overload resolution chooses in this case, we are happy.

In reality, the C# rules (§7.5.3.2) prefer a usual form over an expanded form in such cases, so //B is used. This is a nice thing, the compiler will not have to create an implicit length-1 object array.

like image 31
Jeppe Stig Nielsen Avatar answered Oct 20 '25 19:10

Jeppe Stig Nielsen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!