是否可以在 NUnit 中结合使用 TestCase 和 TestCaseSource/ValueSource?

Is it possible to use combination of TestCase and TestCaseSource/ValueSource in NUnit?

正如标题所说,我想使用 TestCaseTestCaseSource/ValueSource 的组合。

这是一个例子:

public static string[] Source1 = new string[]
{
    "One", "Two", "Three"
};

public static string[] Source2 = new string[]
{
    "Four", "Five", "Six"
};

[TestCase("A"), TestCaseSource(nameof(Source1))]
[TestCase("B"), TestCaseSource(nameof(Source2))]
[TestCase("C"), TestCaseSource(nameof(Source1))]
[TestCase("C"), TestCaseSource(nameof(Source2))]
public void MyTest(string x, string y)
{
    // ...
}

这当然不行,但我想做的是:

有没有可能达到这样的效果?

答案很长,因为我想澄清所涉及的权衡...

我会回答你首先提出的问题:是否可以在 NUnit 中结合使用 TestCase 和 TestCaseSource/ValueSource?

是的,是的。 NUnit 允许您在一个方法上组合任何测试用例数据的来源。

  • TestCase 给你一个测试用例
  • TestCase 源码给你多个测试用例
  • ValueSource 为您提供一个参数的数据(即测试用例的一部分)

在您的示例中,您总共向 MyTest 方法提供了 16 个测试用例。当然,所有这些都是无效的,因为 MyTest 有两个参数,而您的每个测试用例只提供一个值。

从示例中可以看出,您希望放置在相同括号内的属性以某种方式分组。这不是 C# 解释它们的方式。你写的和写的完全一样:

[TestCase("A")]
[TestCase("B")]
[TestCase("C")]
[TestCaseSource(nameof(Source1))]
[TestCaseSource(nameof(Source2))]
[TestCaseSource(nameof(Source1))]
[TestCaseSource(nameof(Source2))]

这不是 NUnit 问题。这就是 C# 属性的工作方式。

因此,虽然可以在同一个方法上组合属性,但不可能以您想要的方式将这些属性的值组合到测试用例中。

NUnit 确实有一种方法可以使用 ValuesValueSource 属性组合值,这适用于各个参数而不是方法。

使用 ValuesAttribute,您可以像这样重写您的示例...

public void MyTest(
    [Values("A", "B", "C")] string x,
    [Values("One", "Two", "Three")] string y )
{
    // ...
}

几乎 适合你,但不完全是。创建了九个案例,("A", "B", "C")("One", "Two", "Three") 的每个可能组合。但是,您希望“B”与“四”、“五”和“六”结合,“C”与第二个参数的所有六个值结合。 ValuesValueSource 都不允许您控制到那种程度。

这让我们回到 TestCaseSource。正如评论中所建议的,您可以使用一种方法通过 TestCaseSourceAttribute 提供测试用例。这是您可以编写此类方法的一种方式...

static IEnumerable<TestCaseData> MySource()
{
    var source1 = new [] { "One", "Two", "Three" };
    var source2 = new [] { "Four", "Five", "Six" };
    var source3 = source1.Concat(source2);

    foreach (var y in source1)
        yield return new TestCaseData("A", y);

    foreach (var y in source2)
        yield return new TestCaseData("B", y);

    foreach (var y in source1)
        yield return new TestCaseData("C", y);
}

也就是说,上面的代码有 12 行,不包括空行,并生成了 12 个测试用例。我自己的方法是避免复杂性以求清晰,并使用一组 TestCaseData 项目专门枚举您想要的案例,例如...

var MySource = new [] {
    new TestCaseData("A", "One"),
    new TestCaseData("A", "Two"),
        etc...
};

这样做的好处是,以后查看代码的任何人都可以轻松理解,包括几个月后的您自己。 :-)