【问题标题】:How to make xUnit to run a Theory parallel?如何使 xUnit 并行运行 Theory?
【发布时间】:2015-09-21 19:20:24
【问题描述】:

我有一个速度很慢的测试(理论)和一堆测试用例。 所以我希望它们同时运行。

我创建了一个简单的例子:

[Theory]
[MyTestData]
public void MyTheory(int num, int sleep)
{
    Console.WriteLine("{0:HH:mm:ss.ffff} - Starting {1} - Sleeping {2}", DateTime.Now, num, sleep);
    Thread.Sleep(sleep);
    Console.WriteLine("{0:HH:mm:ss.ffff} - Finished {1} - Sleeping {2}", DateTime.Now, num, sleep);
}

[AttributeUsage(AttributeTargets.Method)]
public class MyTestDataAttribute : DataAttribute
{
    public override IEnumerable<object[]> GetData(MethodInfo testMethod)
    {
        yield return new object[2] { 1, 5000 };
        yield return new object[2] { 2, 2000 };
        yield return new object[2] { 3, 4000 };
    }
}

运行测试的命令行:

"\packages\xunit.runner.console.2.0.0\tools\xunit.console" "\Projects\xUnitTest\xUnitTest\bin\Debug\xUnitTest.dll" -parallel all > xUnitResult.txt

结果:

xUnit.net console test runner(64-bit.NET 4.0.30319.42000)
Copyright(C) 2015 Outercurve Foundation.

Discovering: xUnitTest
Discovered:  xUnitTest
Starting:    xUnitTest
21:55:39.0449 - Starting 2 - Sleeping 2000
21:55:41.0627 - Finished 2 - Sleeping 2000
21:55:41.0783 - Starting 1 - Sleeping 5000
21:55:46.0892 - Finished 1 - Sleeping 5000
21:55:46.0892 - Starting 3 - Sleeping 4000
21:55:50.0989 - Finished 3 - Sleeping 4000
Finished:    xUnitTest

=== TEST EXECUTION SUMMARY ===
   xUnitTest Total: 3, Errors: 0, Failed: 0, Skipped: 0, Time: 11,137s

这是相当连续的。 我确信可以让它并行。

【问题讨论】:

标签: c# testing xunit xunit.net


【解决方案1】:

这在 xUnit 2.1 中目前是不可能的。根据parallelization docs

默认情况下,每个测试类都是一个唯一的测试集合。同一测试类中的测试不会彼此并行运行。

文档没有明确说明的是:

  • xUnit 中最小的“可并行化”单元是一个集合
  • 同一类中的测试无法位于不同的集合中

通过扩展,并行化的理论是不可能的,因为理论不能分成多个类。


就您而言,这意味着您至少有两个选择:

  • 重构您的测试代码,以便抽象出任何需要花费大量时间的代码。例如,假设您必须运行一些业务逻辑,然后进行数据库调用。如果您可以将可测试的业务逻辑分离到另一个类中,则可以针对该类运行您的理论(不是并行,而是在

  • 如果您的测试用例足够少,只需为每个测试用例创建一个新类并使用Fact 而不是Theory。您甚至可以将它们全部放在一个文件中。它更冗长,你失去了使用理论的“酷”因素,但你会得到并行执行。

【讨论】:

  • xunit 方面的设计决策非常愚蠢。我应该如何运行数以千计的数据驱动测试?
【解决方案2】:

虽然 xUnit 无法直接实现,但如果需要,您可以解决这个问题。缺点是必须通过类手动定义并行执行的数量,因此如果要在两个线程上并行化,则需要创建两个类。

public abstract class ParellelTheoryBase
{
    public static List<int> testValues = new List<int> {1, 2, 3, 4, 5, 6};
}

public class ParallelTheory_1of2 : ParellelTheoryBase
{
    public static List<object[]> theoryData = testValues.Where((data, index) => index % 2 == 0).Select(data => new object[] { data }).ToList();

    [Theory]
    [MemberData(nameof(theoryData))]
    public void DoSomeLongRunningAddition(int data)
    {
        Assert.True(data < 7);
        Thread.Sleep(5000);
    }
}

public class ParallelTheory_2of2 : ParellelTheoryBase
{
    public static List<object[]> theoryData = testValues.Where((data, index) => index % 2 == 1).Select(data => new object[] { data }).ToList();

    [Theory]
    [MemberData(nameof(theoryData))]
    public void DoSomeLongRunningAddition(int data)
    {
        Assert.True(data < 7);
        Thread.Sleep(5000);
    }
}

在本例中,我在ParellelTheoryBase 中定义了属性,它是实际测试类的基类。 然后,ParallelTheory_1of2ParallelTheory_2of2 从该类继承以访问testValues。现在,Theory 使用这个theoryData 执行测试,它只从列表中选择奇数或偶数(index % 2 == 1index % 2 == 0)数据。

它在 Visual Studio 测试资源管理器中被拾取:

并并行运行:

[xUnit.net 00:00:00.3397963]   Starting
[xUnit.net 00:00:15.5696617]   Finished

这可能是一个不容易预先知道您有多少测试数据的解决方案。例如,我在集成测试文件解析器时使用它,其中输入是目录中的任何文件,新添加的文件将自动被提取用于测试。

在您的示例中,我认为您可以轻松修改 MyTestData 属性以接受 totalCountParallelscurrentIndex 的参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    相关资源
    最近更新 更多