如何并行运行NUnit测试?

87

我有一个使用NUnit编写的大型验收测试套件(每个测试约需要10秒)。我想利用我的机器都是多核心的优势。理想情况下,我想让每个核心独立运行一个测试,而不影响其他测试。

虽然有PNUnit,但它是为测试线程同步问题等方面设计的,我没有看到明显的方法可以实现此目标。

是否有开关/工具/选项可供我使用以并行运行测试?


我也想更多地了解这个。@Billy ONeal如果你找到答案,请发表回答。 - P.K
你说每个测试需要十秒钟,理想情况下每个核心运行一个测试。这些测试是否需要大量的CPU资源?否则就可以同时运行更多的测试。 - Mattias Nilsson
@Mattias:是的,这些测试需要大量的CPU资源。 - Billy ONeal
13个回答

59

如果您想并行运行NUnit测试,至少有两个选项:

  • NCrunch可以直接支持(无需更改任何内容,但是它是一个商业产品)
  • NUnit 3提供了一个Parallelizable属性,可以用来标记哪些测试可以并行运行

这个答案似乎与问题无关,更像是一个好的建议而不是真正的答案。在我看来,NCrunch需要你的点赞,并且应该成为最佳答案,因为它可以在相同或多个进程以及跨一个或多台机器上并发运行(NUnit)测试,并且可以从VS或构建服务器中运行。 - chillitom
3
在回答这个问题之后,NCrunch发布了,它是一个不错的选择(因为它应该可以直接使用,尽管对于某些人来说价格过高)。未来的其他选择可能包括NUnit 3,它可能会提供测试的并行运行功能(根据https://github.com/nunit/dev/wiki/Roadmap)。 - David_001
3
尽管这是最佳答案,但它现在不再像之前一样正确。Nunit 3.0于2015年底发布,其中现在具有Parallelizable属性。参考:https://github.com/nunit/nunit/wiki/Parallelizable-Attribute - pb.

38

NUnit 3版本将支持并行运行测试:

将属性[Parallelizable(ParallelScope.Self)]添加到一个类中,将会并行运行测试用例。

• ParallelScope.None表示该测试用例不能与其他测试用例同时运行。

• ParallelScope.Self表示该测试用例本身可以与其他测试用例同时运行。

• ParallelScope.Children表示该测试用例的子代可以相互之间并行运行。

• ParallelScope.Fixtures表示测试套件可以相互之间并行运行。

NUnit Framework-Parallel-Test-Execution


10

如果您的项目包含多个测试DLL,您可以使用此MSBuild脚本并行运行它们。显然,您需要调整路径以适应您的项目布局。

要使用8个核心运行,请使用以下命令: c:\proj> msbuild /m:8 RunTests.xml

RunTests.xml

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="RunTestsInParallel" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
    <Nunit Condition=" '$(Nunit)' == '' ">$(MSBuildProjectDirectory)\..\tools\nunit-console-x86.exe</Nunit>
  </PropertyGroup>

  <!-- see http://mikefourie.wordpress.com/2010/12/04/running-targets-in-parallel-in-msbuild/ -->

  <Target Name="RunTestsInParallel">
    <ItemGroup> 
      <TestDlls Include="..\bin\Tests\$(Configuration)\*.Tests.dll" />
    </ItemGroup>

    <ItemGroup> 
      <TempProjects Include="$(MSBuildProjectFile)" > 
        <Properties>TestDllFile=%(TestDlls.FullPath)</Properties> 
      </TempProjects> 
    </ItemGroup> 

    <MSBuild Projects="@(TempProjects)" BuildInParallel="true" Targets="RunOneTestDll" /> 
  </Target>

  <Target Name="RunOneTestDll"> 
    <Message Text="$(TestDllFile)" />
    <Exec Command="$(Nunit) /exclude=Integration $(TestDllFile)  /labels /xml:$(TestDllFile).results.xml"
      WorkingDirectory="$(MSBuildProjectDirectory)\..\bin\Tests\$(Configuration)" /> 
  </Target>

</Project>

更新 如果现在我回答这个问题,我强烈推荐使用 NCrunch 和它的命令行测试运行工具来获得最大的测试运行性能。它无与伦比,同时还会彻底改变您的代码-测试-调试循环。


1
这帮助我将单元测试运行时间从3分钟减少到2分钟。我已在一台双核CPU上进行了测试。 - Dmitrii Lobanov

8
作为替代方案,每个测试类添加Parallelizable属性的方法如下:
在nunit3或更高版本的测试项目AssemblyInfo.cs类中添加以下内容:
// Make all tests in the test assembly run in parallel
[assembly: Parallelizable(ParallelScope.Fixtures)]

1
我必须使用 [assembly: Parallelizable(ParallelScope.All)] - Ned
2
正确答案实际上是在AssemblyInfo.cs中使用[assembly: Parallelizable(ParallelScope.ContextMask)]ContextMask没有文档记录,但是如果您打开Enum,您会发现 ContextMask = (ParallelScope.Fixtures | ParallelScope.Children)这意味着除非您为特定的类、方法或测试设置不同的值,否则此程序集中存在的每个单元测试都将被视为可并行化。 - Moscato

4
这篇文章中提到,为了加速测试,发帖者运行多个NUnit实例,并使用命令参数指定每个实例应该运行哪些测试。
FTA:
“我遇到了一个奇怪的问题。我们使用nunit-console在我们的持续集成服务器上运行测试。最近,我们从Nunit 2.4.8升级到2.5.5,并从.Net 3.5升级到4.0。为了加快测试执行速度,我们并行运行多个不同命令行参数的Nunit实例。”
  • 我们有两份测试程序集和nunit二进制文件在文件夹A和B中。
  • 在文件夹A中,我们执行:

nunit-console-x86.exe Model.dll Test.dll /exclude:MyCategory /xml=TestResults.xml /framework=net-4.0 /noshadow

  • 在文件夹B中,我们执行:

nunit-console-x86.exe Model.dll Test.dll /include:MyCategory /xml=TestResults.xml /framework=net-4.0 /noshadow

如果我们按顺序执行这些命令,两个都会成功运行。但是如果我们并行执行它们,只有一个会成功。据我所知,它是首先加载测试夹具的那个。另一个会失败,并显示“无法找到固定装置”的消息。
这个问题已经被解决了,或者您没有运行上述软件的新版本,则应该能够复制他们的技术。
更新 TeamCity看起来是一个可以用来自动运行NUnit测试的工具。他们有一个NUnit启动器,在这里讨论,可以用来启动多个NUnit实例。 这里是一篇博客文章,讨论了将多个NUnit XML结果合并为单个结果文件的方法。
因此,理论上,您可以让TeamCity根据您想要如何拆分工作量自动启动多个NUnit测试,然后将结果合并为单个文件以进行后处理。
对于您的需求,这是否足够自动化?

这个想法已经在类别中发布过了...我不想在这里维护合理的相等运行时间。我宁愿在这之前编写自己的 NUnit 运行器。 - Billy ONeal
据我所知,NUnit没有直接支持此功能,除非采用一些变通方法,例如运行多个实例。如果您愿意,可以编写一个工具将测试分成N组,并自动运行N个 NUnit 实例,其中 N 是您拥有的处理器/核心数。这是我能想到的使用 NUnit 进行某种形式的自动并行测试的唯一方法。 - kniemczak
我添加了一篇更新,讨论了TeamCity持续集成工具,并包括一些关于如何使用该工具解决自动化需求的文章。 - kniemczak

3
仅仅因为PNUnit可以在测试代码中进行同步,并不意味着你必须使用这一方面。据我所见,没有任何防止你只生成一个集合并忽略其余部分直到需要它们的东西。
顺便说一下,我没有时间阅读所有的源代码,但是很想查看Barrier类,它是一个非常简单的锁计数器。它只等待N个线程进入,然后发送脉冲让它们同时继续运行。就是这样 - 如果你不碰它,它不会伤害你。
对于普通的线程开发来说可能有点反直觉(锁通常用于序列化访问 - 逐个进行),但这是一个相当有趣的偏离 :-)

3

现在您可以使用NCrunch来并行执行单元测试,甚至可以配置NCrunch使用多少核心以及Visual Studio使用多少核心。

此外,您还可以获得连续测试的额外优势 :)


3
在Visual Studio中使用NCrunch非常好,但在尝试在构建服务器上并行化测试时,它无法提供帮助。 - Paccc
3
NCrunch 现在拥有一个命令行工具,非常适用于构建服务器。 - chillitom

2
您可以尝试我的小型工具TBox,或者控制台并行Runner甚至是插件来进行分布式计算,这也可以在一组PC上运行单元测试SkyNet
TBox的创建是为了简化与包含许多项目的大型解决方案的工作。它支持许多插件之一提供了并行运行NUnit测试的功能。该插件不需要对现有测试进行任何更改。
它还支持:
  • 克隆带有单元测试的文件夹(如果您的测试更改本地数据),

  • 同步测试(例如,如果您的测试在testfixtureteardown上杀死所有开发服务器或chromerunner用于qunit),

  • x86模式和管理员权限以运行测试,

  • 批量运行-您可以并行运行多个程序集的测试,

  • 即使是单线程运行,也比标准nunit运行器快,如果您有许多小型测试。

此外,该工具支持命令行测试运行程序(用于并行运行),您可以将其与持续集成一起使用。


如果您与此产品有关,请披露这一点。您已发布多个指向此产品的内容。 - Brad Larson
当然,TBox是我的自己的工具。我是独自在空闲时间编写的。如果在这里谈论免费工具是不好的做法,我会删除这个回答,没有问题 :) - Alex H
我们只希望人们清楚地了解他们所涉及的产品。如果您充分披露这是您自己的产品,并说明为什么它适合解决问题,而且不要过于积极地推销,那么您的回答应该是可以接受的。 - Brad Larson
@brad 它在 Codeplex 上是开源的,不确定为什么会有问题。 - dvallejo
@DanVallejo - 作为一个开源项目,这就是为什么社区在发布后没有删除它的原因。我们在这方面给予了一些更多的自由度,但我们仍然要求您披露与该项目的关联,以便人们可以理解您的推荐背后的上下文。Alex在这里做到了,所以他的答案现在完全没问题。 - Brad Larson

2

这可能有点作弊,但你可以将单元测试分成多个类别。然后,为每个类别启动一个新的 NUnit 实例。

编辑:看起来他们已经在控制台应用程序中添加了 /process 选项。命令行帮助说明这是“测试的进程模型:单个、独立、多个”。测试运行器似乎也具备此功能。

编辑2:不幸的是,虽然它确实为每个程序集创建了单独的进程,但进程隔离选项(命令行中的 /process)一次只运行一个代理。


2

由于这个项目在这里还没有提到,我想介绍一下NUnit.Multicore。虽然我自己没有尝试过这个项目,但它似乎对NUnit并行测试问题有一个有趣的解决方案。


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