运行长时间运行的NUnit / xUnit测试,以便它们不会阻塞其他测试。

3

我正在运行一组集成测试,大部分测试都能在合理的时间范围内完成,但有两个测试需要等待特定条件(精确到金融市场条件),可能需要持续2-3个小时。因此,我希望实现以下两点:

  1. 在其他测试完成后再开始这两个测试
  2. 并行运行它们

是否有办法在NUnit / XUnit(或其他测试运行器)中实现这一点?


你可以在不同的进程中运行测试 - Fabio
2个回答

3
  1. 并行测试运行取决于测试运行器的参数。如果您使用 xUnit 控制台测试运行器,则可以使用 -parallel 参数或 MSBuild 选项,参见:https://xunit.net/docs/running-tests-in-parallel。但无论如何,您都必须将长时间运行的测试拆分为单独的测试类。

  2. 更难保证测试运行的顺序,您可以使用 TestCollection(但根据指南集合按顺序运行)。您可以重命名长时间运行的测试以将它们放在列表末尾,即 TestClass2 将在 TestClass1 之后执行。您还可以使用类别属性参数将测试分开,并通过 2 个命令运行它们:dotnet test --filter=TestCategory=LongTests(一个用于长时间运行的测试,另一个用于其他测试),请参见 https://learn.microsoft.com/ru-ru/dotnet/core/testing/selective-unit-tests?pivots=mstest


3

在其他测试完成后启动这两个测试

您可以将这两个测试保留在单独的NUnit测试项目中,以便您可以单独运行所有其他测试。

关于并行运行测试,此博客有一篇不错的文章:

https://blog.sanderaernouts.com/running-unit-tests-in-parallel-with-nunit

请标记您的测试夹具为Parallelizable属性,并将并行范围设置为ParallelScope.All。 创建一个名为TestScope的私有类,并实现IDisposable接口。 将所有启动和清理逻辑放置在TestScope构造函数和.Dispose()方法中。 将您的测试代码包装在using (var scope = new TestScope) { ... }块中。
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class MyClassTests {

    [Test]
    public void MyParallelTest() {
        using(var scope = new TestScope()) {
            scope.Sut.DoSomething();
            scope.Repository.Received(1).Save();
        }
    }

    private sealed class TestScope : IDisposable {
        public IRepository Repository{get;}
        public MyClass Sut {get;}
        public TestScope() {
            Repository = Substitute.For<IRepository>();
            Sut = new MyClass(Repository);
        }

        public void Dispose() {
            //clean-up code goes here
            Repository?.Dispose()
        }
    }
}

你应该采取预防措施,以确保在并行运行时,你的测试不会互相干扰。
正如文章所述:
“如何安全地并行运行测试”
为了允许测试并行运行而不相互干扰,我已经应用以下模式有一段时间了:
- 创建一个嵌套的私有TestScope类,实现IDisposable。 - 所有初始化或启动代码应放在TestScope类的构造函数中,SetUp方法中的所有初始化或启动代码都应放在TestScope类的构造函数中。 - 任何清理或拆卸代码都应放在Dispose方法中,这就相当于TearDown方法。所有测试都在使用块中运行,该块处理TestScope的创建和处理。
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class MyClassTests {

    [Test]
    public void MyParallelTest() {
        using(var scope = new TestScope()) {
            scope.Sut.DoSomething();
            scope.Repository.Received(1).Save();
        }
    }

    private sealed class TestScope : IDisposable {
        public IRepository Repository{get;}
        public MyClass Sut {get;}
        public TestScope() {
            Repository = Substitute.For<IRepository>();
            Sut = new MyClass(Repository);
        }

        public void Dispose() {
            //clean-up code goes here
            Repository?.Dispose()
        }
    }
}

这篇文章提供了更有价值的建议。我建议阅读它,并感谢作者。

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