连续执行单元测试(而不是并行执行)

jri*_*sta 74 .net c# unit-testing xunit.net

我正在尝试对我编写的WCF主机管理引擎进行单元测试.该引擎基本上基于配置动态创建ServiceHost实例.这允许我们动态地重新配置哪些服务可用,而无需在添加新服务或删除旧服务时将其全部关闭并重新启动它们.

但是,由于ServiceHost的工作方式,我在单元测试此主机管理引擎时遇到了困难.如果已为特定端点创建,打开和尚未关闭ServiceHost,则无法创建同一端点的另一个ServiceHost,从而导致异常.由于现代单元测试平台并行化了他们的测试执行,我没有有效的方法对这段代码进行单元测试.

我使用过xUnit.NET,希望由于它的可扩展性,我可以找到一种方法来强制它以串行方式运行测试.但是,我没有运气.我希望SO上的某个人遇到类似的问题并且知道如何让单元测试连续运行.

注意:ServiceHost是一个由Microsoft编写的WCF类.我没有能力改变它的行为.仅托管每个服务端点也是正确的行为......但是,它不是特别有利于单元测试.

Squ*_*gle 86

如上所述,所有良好的单元测试应该是100%隔离的.使用共享状态(例如,取决于static每个测试修改的属性)被视为不良做法.

话虽如此,关于按顺序运行xUnit测试的问题确实有答案!我遇到了完全相同的问题,因为我的系统使用静态服务定位器(不太理想).

默认情况下,xUnit 2.x并行运行所有测试.通过CollectionBehavior在测试项目中的AssemblyInfo.cs中定义,可以对每个程序集进行修改.

对于每个组件分离使用:

using Xunit;
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
Run Code Online (Sandbox Code Playgroud)

或者根本没有并行化:

[assembly: CollectionBehavior(DisableTestParallelization = true)]
Run Code Online (Sandbox Code Playgroud)

后者可能就是你想要的那个.有关并行化和配置的更多信息,请参见xUnit文档.

  • 对我来说,每个类中的方法之间都有共享资源.从一个类运行测试,然后从另一个类运行测试将破坏两者的测试.我能够通过使用`[assembly:CollectionBehavior(CollectionBehavior.CollectionPerClass,DisableTestParallelization = true)]`来解决.谢谢你,@ Squiggle,我可以运行所有测试并去喝咖啡!:) (5认同)
  • 对于.NET Core,来自Abhinav Saxena的答案更为详尽。 (2认同)
  • 这在 .NET Core 中也适用于我。 (2认同)

Abh*_*ena 74

每个测试类都是一个独特的测试集合,其下的测试将按顺序运行,因此如果您将所有测试放在同一个集合中,那么它将按顺序运行.

在xUnit中,您可以进行以下更改以实现此目的:

以下将并行运行:

namespace IntegrationTests
{
    public class Class1
    {
        [Fact]
        public void Test1()
        {
            Console.WriteLine("Test1 called");
        }

        [Fact]
        public void Test2()
        {
            Console.WriteLine("Test2 called");
        }
    }

    public class Class2
    {
        [Fact]
        public void Test3()
        {
            Console.WriteLine("Test3 called");
        }

        [Fact]
        public void Test4()
        {
            Console.WriteLine("Test4 called");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要使其顺序,您只需将两个测试类放在同一个集合下:

namespace IntegrationTests
{
    [Collection("Sequential")]
    public class Class1
    {
        [Fact]
        public void Test1()
        {
            Console.WriteLine("Test1 called");
        }

        [Fact]
        public void Test2()
        {
            Console.WriteLine("Test2 called");
        }
    }

    [Collection("Sequential")]
    public class Class2
    {
        [Fact]
        public void Test3()
        {
            Console.WriteLine("Test3 called");
        }

        [Fact]
        public void Test4()
        {
            Console.WriteLine("Test4 called");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅此链接

  • 我认为,未得到回应的答案.似乎工作,我喜欢粒度,因为我在一个程序集中具有可并行化和不可并行化的测试. (17认同)
  • 这应该是公认的答案,因为通常有些测试可以并行运行(在我的例子中是所有单元测试),但有些测试在并行运行时会随机失败(在我的例子中使用内存中的 Web 客户端/服务器),所以一个是如果愿意的话可以优化测试运行。 (6认同)
  • 在我使用 sqlite 数据库执行集成测试的 .net core 项目中,这对我不起作用。测试仍然并行执行。不过,接受的答案确实有效。 (3认同)
  • 这是执行此操作的正确方法,请参阅 Xunit 文档。 (2认同)

Dmi*_*nov 52

对于.NET Core项目,使用以下命令创建xunit.runner.json:

{
  "parallelizeAssembly": false,
  "parallelizeTestCollections": false
}
Run Code Online (Sandbox Code Playgroud)

另外,你csproj应该包含

<ItemGroup>
  <None Update="xunit.runner.json"> 
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

对于旧的.Net Core项目,您project.json应该包含

"buildOptions": {
  "copyToOutput": {
    "include": [ "xunit.runner.json" ]
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这在csproj中适用于我:`<ItemGroup> <None Update ="xunit.runner.json"> <CopyToOutputDirectory> PreserveNewest </ CopyToOutputDirectory> </ None> </ ItemGroup> (3认同)
  • 我假设最新的csproj dotnet核心等价物是`<ItemGroup> <None Include ="xunit.runner.json"CopyToOutputDirectory ="Always"/> </ ItemGroup>`或类似的? (2认同)

Mar*_*ery 17

对于.NET Core项目,您可以使用xunit.runner.json文件配置xUnit ,如https://xunit.github.io/docs/configuring-with-json.html中所述.

您需要更改以停止并行测试执行的parallelizeTestCollections设置,默认为true:

true如果程序集愿意在此程序集内并行运行测试,则将此设置为....将此设置false为禁用此测试程序集中的所有并行化.

JSON模式类型:boolean
默认值:true

因此xunit.runner.json,这个目的的最小化看起来像

{
    "parallelizeTestCollections": false
}
Run Code Online (Sandbox Code Playgroud)

如文档中所述,请记住在您的构建中包含此文件,方法是:

  • 复制到输出目录设置为复制如果文件在Visual Studio中的属性更新,或者
  • 添加

    <Content Include=".\xunit.runner.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    
    Run Code Online (Sandbox Code Playgroud)

    到你的.csproj文件,或

  • 添加

    "buildOptions": {
      "copyToOutput": {
        "include": [ "xunit.runner.json" ]
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    到你的project.json文件

取决于您的项目类型.

最后,除了上述内容之外,如果您正在使用Visual Studio,那么请确保您没有意外地单击"并行运行测试"按钮,这将导致测试并行运行,即使您已关闭并行化xunit.runner.json.微软的UI设计人员狡猾地将这个按钮取消标记,很难注意到,并且距离测试资源管理器中的"全部运行"按钮大约一厘米,只是为了最大限度地提高您误操作的机会,并且不知道为什么要进行测试突然失败了:

带有按钮的屏幕截图


Gün*_*ZER 15

这是一个老问题,但我想为像我这样新搜索的人写一个解决方案:)

注意:我在使用 xunit 版本 2.4.1 的 Dot Net Core WebUI 集成测试中使用此方法。

创建一个名为 NonParallelCollectionDefinitionClass 的空类,然后将 CollectionDefinition 属性赋予该类,如下所示。(重要的部分是 DisableParallelization = true 设置。)

using Xunit;

namespace WebUI.IntegrationTests.Common
{
    [CollectionDefinition("Non-Parallel Collection", DisableParallelization = true)]
    public class NonParallelCollectionDefinitionClass
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将 Collection 属性添加到您不希望它并行运行的类,如下所示。(重要的部分是集合的名称。它必须与 CollectionDefinition 中使用的名称相同)

namespace WebUI.IntegrationTests.Controllers.Users
{
    [Collection("Non-Parallel Collection")]
    public class ChangePassword : IClassFixture<CustomWebApplicationFactory<Startup>>
    ...
Run Code Online (Sandbox Code Playgroud)

当我们这样做时,首先运行其他并行测试。之后运行具有 Collection("Non-Parallel Collection") 属性的其他测试。


HB *_*AAM 6

您可以使用播放列表

右键单击测试方法->添加到播放列表->新播放列表

然后您可以指定执行顺序,默认顺序是将它们添加到播放列表时的顺序,但是您可以根据需要更改播放列表文件

在此处输入图片说明


Tru*_*ill 5

我不知道细节,但是听起来您可能正在尝试进行集成测试而不是单元测试。如果您可以隔离对的依赖关系ServiceHost,则可能会使您的测试更加轻松(而且速度更快)。因此,(例如)您可以独立测试以下内容:

  • 配置阅读课
  • ServiceHost工厂(可能是集成测试)
  • 带有IServiceHostFactory和的引擎类IConfiguration

可以帮助使用的工具包括隔离(模拟)框架和(可选)IoC容器框架。看到:


Gra*_*ton 5

也许您可以使用高级单元测试它允许您定义运行测试的顺序。因此,您可能必须创建一个新的 cs 文件来托管这些测试。

以下是如何调整测试方法以按您想要的顺序工作。

[Test]
[Sequence(16)]
[Requires("POConstructor")]
[Requires("WorkOrderConstructor")]
public void ClosePO()
{
  po.Close();

  // one charge slip should be added to both work orders

  Assertion.Assert(wo1.ChargeSlipCount==1,
    "First work order: ChargeSlipCount not 1.");
  Assertion.Assert(wo2.ChargeSlipCount==1,
    "Second work order: ChargeSlipCount not 1.");
  ...
}
Run Code Online (Sandbox Code Playgroud)

请告诉我它是否有效。

  • 等等,首先你说你不希望测试并行运行,然后你说问题是测试运行程序不并行运行测试......那么哪个是哪个? (2认同)