如何在NUNIT TestCase中添加新的List<int> {1}?

56

我有这个方法:

public static int Add(List<int> numbers)
    {
        if (numbers == null || numbers.Count == 0)
            return 0;

        if (numbers.Count == 1)
            return numbers[0];


        throw new NotImplementedException();
    }

这是我的测试代码,但它不喜欢 TestCase 中的 new List<int> {1}:

    [TestCase(new List<int>{1}, 1)]
    public void Add_WithOneNumber_ReturnsNumber(List<int> numbers)
    {

        var result = CalculatorLibrary.CalculatorFunctions.Add(numbers);

        Assert.AreEqual(1, result);
    }

它给了我这个错误:

一个属性参数必须是常量表达式、typeof表达式或属性参数类型的数组创建表达式

我是不是要像这样做:

    [Test]
    public void Add_WithOneNumber_ReturnsNumber()
    {

        var result = CalculatorLibrary.CalculatorFunctions.Add(new List<int>{7});


        Assert.AreEqual(7, result);

        var result2 = CalculatorLibrary.CalculatorFunctions.Add(new List<int> {3});

        Assert.AreEqual(4,result2);
    }

在TestCase中,您将无法使用非常量表达式。 - Yurii Hohan
@YuriiHohan - 我唯一的选择是我发布的新测试吗? - xaisoft
你可能想在这里使用TestCaseSource而不是TestCasehttp://www.nunit.org/index.php?p=testCaseSource&r=2.5 - Preston Guillot
8个回答

74

有一种选项可以使用TestCaseSource属性。在这里,我提供了一个非断言测试,其中包含两个案例,只是为了展示其工作原理:

[TestFixture]
public class TestClass
{
    private static readonly object[] _sourceLists = 
    {
        new object[] {new List<int> {1}},   //case 1
        new object[] {new List<int> {1, 2}} //case 2
    };

    [TestCaseSource("_sourceLists")]
    public void Test(List<int> list)
    {
        foreach (var item in list)
            Console.WriteLine(item);
    }
}

无论如何,我必须提到这不是最明显的解决方案,我更喜欢整洁有序的固定装置,尽管它们更冗长。

更多信息: https://github.com/nunit/docs/wiki/TestCaseSource-Attribute


你能用一个例子澄清一下你最后的评论吗?另外,从另一个测试中实际调用另一个测试是可能的吗?还是这是不好的做法? - xaisoft
顺便说一句,这个可以工作,但我同意它有点奇怪。我可能更喜欢更简洁和整洁的测试。 - xaisoft
我不明白在类中创建一个“私有”列表数组,然后通过属性引用它们的价值所在。并不是要失礼,只是不理解这比Test()方法没有参数并在测试方法本身生成列表更好在哪里。这个列表是否在其他测试方法中被重复使用?如果是,那么“Setup()`类型方法是否更有用呢? - Karl Anderson
我在答案中陈述的并不是更好的方法,而只是库允许的做法。 - Yurii Hohan
4
针对你的评论更新,使用以下内容: private static readonly object[] _Data = { new object[] {new List<int> {0}, "测试"}, new object[] {new List<int> {0, 5}, "测试这个"}, };[Test, TestCaseSource(nameof(_Data))] - zquanghoangz
显示剩余3条评论

29

我的解决方案更简单,我只是使用 params。希望对你有用!

[TestCase(1, 1)]
[TestCase(10, 5, 1, 4)]
[TestCase(25, 3, 5, 5, 12)]
public void Linq_Add_ShouldSumAllTheNumbers(int expected, params int[] numbers)
{
    var result = CalculatorLibrary.CalculatorFunctions.Add(numbers);
    Assert.AreEqual(expected, result);
}

6
那并未回答问题。你正在使用恒定的基元。请尝试使用除编译时常量以外的任何东西来测试。 - Timothy Gonzalez

11

改进@Yurii Hohan答案的代码:

private  static readonly object[] _Data =
        {
            new object[] {new List<int> {0}, "test"},
            new object[] {new List<int> {0, 5}, "test this"},
        };

[Test, TestCaseSource(nameof(_Data))]

希望这能有所帮助。


9
您可以使用这个:
[TestCase(new []{1,2,3})]
public void Add_WithOneNumber_ReturnsNumber(int[] numbers)

那不是一个列表,而是一个数组。OP必须将其转换为列表。 - LarryBud
1
在我看来,这是最好的方法。是的,这不是List,但如果需要,在测试源代码中可以轻松转换为List。当我需要将List传递给测试时,我通常会这样做。 - Vlad

9
我经常使用字符串和解析,因为它在测试运行器中呈现得很好。示例:
[TestCase("1, 2")]
[TestCase("1, 2, 3")]
public void WithStrings(string listString)
{
    var list = listString.Split(',')
                         .Select(int.Parse)
                         .ToList();
    ...
}

在Resharper的运行器中,看起来像这样:

在此输入图片描述


6

在测试用例中使用数组作为参数new [] {1, 2},并在测试方法内将其转换为列表numbers.ToList()

using System.Linq
...

[TestCase(new [] {1}, 1)]
[TestCase(new [] {1, 2}, 3)]
[TestCase(new [] {1, 2, 3}, 6)]
public void Return_sum_of_numbers(int[] numbers, int expectedSum)
{
    var sum = CalculatorLibrary.CalculatorFunctions.Add(numbers.ToList());

    Assert.AreEqual(expectedSum, sum );
    // much cooler with FluentAssertions nuget:
    // sum.Should.Be(expectedSum);
}

-2

在数据属性中,您不能仅使用对象编译时常量。为了避免使用反射,我发现它非常难以阅读,并且不适合于旨在尽可能清晰地描述行为的测试,这里是我的做法:

    [Test]
    public void Test_Case_One()
    {
        AssertCurrency(INPUT, EXPECTED);
    }

    [Test]
    public void Test_Case_Two()
    {
        AssertCurrency(INPUT, EXPECTED);
    }

    private void AssertScenario(int input, int expected)
    {
        Assert.AreEqual(expected, input);
    }

这是几行代码,但只是因为我想要清晰的测试输出。如果你想要更简洁的东西,你也可以把它们放在一个[Test]中。


-4

只需在方法内部创建列表,像这样:

public void Add_WithOneNumber_ReturnsNumber()
{
    var result = CalculatorLibrary.CalculatorFunctions.Add(new List<int>{1});

    Assert.AreEqual(1, result);
}

这是否意味着我必须为3和7分别编写单独的测试,而不能使用TestCase? - xaisoft
如果37测试不同的事情,那么是的,你需要为每个测试编写不同的测试用例。如果它们只是两个值,都执行相同的测试,那么不需要。 - Karl Anderson
我如何在我的测试中包含3和7? 我能想到的唯一方法是实例化两个列表,分别添加这两个数字,然后调用Add方法。所以基本上,我的测试就像一个测试用例一样运行。我理解的对吗? - xaisoft
我的唯一选择是我发布的新测试吗? - xaisoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接