简体   繁体   English

如何并行运行单元测试(MSTest)?

[英]How to run unit tests (MSTest) in parallel?

I am looking for ways to run test suites in parallel.我正在寻找并行运行测试套件的方法。

I am aware of .testrunconfig setting.我知道.testrunconfig设置。 This allows you to multiplex on the number of CPUs.这允许您多路复用CPU 的数量。

I want to run 1000 tests in parallel.我想并行运行 1000 个测试。 This makes sense because I am testing a web service, so 90% of the time spent in a test is waiting for the service to respond.这是有道理的,因为我正在测试一个 Web 服务,所以在测试中花费的 90% 的时间都在等待服务响应。

Any ideas on how to pull this off ?关于如何解决这个问题的任何想法? The tests are written for VS, but I am open to running them outside of VS.这些测试是为 VS 编写的,但我愿意在 VS 之外运行它们。

Later edit : the Visual Studio test team have added this in VS 2015 Update 1. See Mark Sowul's answer bellow.稍后编辑:Visual Studio 测试团队已在 VS 2015 Update 1 中添加了此内容。请参阅下面的 Mark Sowul 回答。

Most of the answers on this page forget to mention that MSTest parallelizes tests in separate assemblies .此页面上的大多数答案都忘记提及 MSTest将单独程序集中的测试并行化。 You have to split your unittests into multiple .dll's to paralelize it.您必须将单元测试拆分为多个 .dll 以对其进行并行化。

But!但是! The recent version - MSTest V2 - now CAN parallelize "in-assembly" (yay!) you just need to install a couple of nuget packages in your test project - TestFramework and TestAdapter - like described here https://blogs.msdn.microsoft.com/devops/2018/01/30/mstest-v2-in-assembly-parallel-test-execution/最近的版本- MSTest的V2 -现在可以并行“在组装”(!耶),你只需要安装一对夫妇的NuGet包的测试项目- TestFramework和TestAdapter -喜欢这里描述https://blogs.msdn.microsoft .com/devops/2018/01/30/mstest-v2-in-assembly-parallel-test-execution/

And then simply add this to your test project然后只需将其添加到您的测试项目中

[assembly: Parallelize(Workers = 4, Scope = ExecutionScope.ClassLevel)]

EDIT: You can also disable parallel execution for a specific test using [DoNotParallelize] on a test method.编辑:您还可以在测试方法上使用[DoNotParallelize]禁用特定测试的并行执行。

You can get up to 5 by using the method from the Visual Studio Team Test Blog使用Visual Studio 团队测试博客中的方法最多可以获得 5 个

Keep in mind that there may be concurrency issues using this, as MSTest doesn't completely isolate each test (statics carry over, for example, making things interesting for code meant to run once).请记住,使用它可能存在并发问题,因为 MSTest 并没有完全隔离每个测试(例如,静态结转,使原本打算运行一次的代码变得有趣)。

(No idea why the limit is 5, but MSTest will not run them in parallel if parallelTestCount is set to more than 5. As per the comments below, this rule apparently changes with Visual Studio 2013) (不知道为什么限制是 5,但如果parallelTestCount设置为 5 以上,MSTest 将不会并行运行它们。根据下面的评论,此规则显然随 Visual Studio 2013 更改)

Visual Studio 2015 Update 1 adds this. Visual Studio 2015 Update 1 添加了这个。 https://docs.microsoft.com/visualstudio/releasenotes/vs2015-update1-vs#misc https://docs.microsoft.com/visualstudio/releasenotes/vs2015-update1-vs#misc

For Update 2, there is a UI toggle button in the toolbar at the top of the Test Explorer pane (between the 'grouping' and 'search' boxes).对于更新 2,测试资源管理器窗格顶部的工具栏中有一个 UI 切换按钮(在“分组”和“搜索”框之间)。

For Update 1, Set the following in the .runsettings对于更新 1,在 .runsettings 中设置以下内容

<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
  <RunConfiguration>
    <MaxCpuCount>0</MaxCpuCount>
   </RunConfiguration>
</RunSettings>

The value for MaxCpuCount has the following semantics: MaxCpuCount 的值具有以下语义:

• 'n' (where 1 <= n <= number of cores) : upto 'n' processes will be launched. • “n”(其中 1 <= n <= 内核数):最多将启动“n”个进程。

• 'n' of any other value : The number of processes launched will be as many as the available cores on the machine. • 任何其他值的“n”:启动的进程数将与机器上的可用内核数一样多。

What I found is that C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe will run parallel tests with a .testsettings file which looks like this:我发现 C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe 将使用.testsettings文件运行并行测试,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name="TestSettings1" id="21859d0f-7bdc-4165-b9ad-05fc803c9ee9" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
  <Description>These are default test settings for a local test run.</Description>
  <Deployment enabled="false" />
  <Execution parallelTestCount="8">
    <TestTypeSpecific>
      <UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
        <AssemblyResolution>
          <TestDirectory useLoadContext="true" />
        </AssemblyResolution>
      </UnitTestRunConfig>
    </TestTypeSpecific>
    <AgentRule name="Execution Agents">
    </AgentRule>
  </Execution>
</TestSettings>

Reference can be found here http://msdn.microsoft.com/en-us/library/vstudio/jj155796.aspx参考可以在这里找到http://msdn.microsoft.com/en-us/library/vstudio/jj155796.aspx

The above answers definitely helped clarify things for me, but, this point from John Koerner's blog: https://johnkoerner.com/vs2015/parallel-test-execution-in-visual-studio-2015-update-1-might-not-be-what-you-expect/ was the bit we were missing.以上答案确实帮助我澄清了事情,但是,这一点来自 John Koerner 的博客: https : //johnkoerner.com/vs2015/parallel-test-execution-in-visual-studio-2015-update-1-might-not -be-what-you-expect/是我们遗漏的一点。

"Parallel test execution leverages the available cores on the machine, and is realized by launching the test execution engine on each available core as a distinct process, and handing it a container (assembly, DLL, or relevant artifact containing the tests to execute), worth of tests to execute." “并行测试执行利用机器上的可用内核,并通过在每个可用内核上将测试执行引擎作为一个不同的进程启动,并将其交给一个容器(程序集、DLL 或包含要执行的测试的相关工件)来实现,值得执行的测试。”

--> "The separate container bit is the piece I was missing. In order to get my tests to run in parallel, I needed to split up my tests into separate test assemblies. After doing that, I saw that the tests in different assemblies were running in parallel." --> "单独的容器位是我缺少的部分。为了让我的测试并行运行,我需要将我的测试拆分成单独的测试程序集。这样做之后,我看到不同程序集中的测试并行运行。”

So yeah, we got the tests running in parallel in VSTS by using their handy 'run in parallel' flag, but it wasn't enough, we had to split our tests up into separate test projects.所以是的,我们通过使用他们方便的“并行运行”标志让测试在 VSTS 中并行运行,但这还不够,我们不得不将我们的测试分成单独的测试项目。 Logically grouped of course, not a project-per-test which would be ridiculous当然按逻辑分组,而不是每个测试的项目,这很荒谬

  1. Ensure the first column in your DataTable is a unique Id.确保数据表中的第一列是唯一的 ID。
  2. Create a AsyncExecutionTask delegate that accepts a DataRow and returns nothing.创建一个接受 DataRow 并且不返回任何内容的 AsyncExecutionTask 委托。
  3. Create a static class (ParallelTesting) with a AsyncExecutionContext method that accepts a DataRow and an AsyncExecutionTask delegate.使用接受 DataRow 和 AsyncExecutionTask 委托的 AsyncExecutionContext 方法创建静态类 (ParallelTesting)。
  4. In the static class add a static BatchStarted property.在静态类中添加一个静态的 BatchStarted 属性。
  5. In the static class add a static AsyncExecutionTests Dictionary property.在静态类中添加一个静态 AsyncExecutionTests Dictionary 属性。
  6. In the AsyncExecutionContext method add the following:在 AsyncExecutionContext 方法中添加以下内容:

     public static void AsyncExecutionContext(DataRow currentRow, AsyncExecutionTask test) { if(!BatchStarted) { foreach(DataRow row in currentRow.Table) { Task testTask = new Task(()=> { test.Invoke(row); }); AsyncExecutionTests.Add(row[0].ToString(), testTask); testTask.Start(); } BatchStarted = true; } Task currentTestTask = AsyncExecutionTests[row[0].ToString()]; currentTestTask.Wait(); if(currentTestTask.Exception != null) throw currentTestTask.Exception; }
  7. Now use the class like so:现在像这样使用这个类:

     [TestMethod] public void TestMethod1() { ParallelTesting.AsyncExecutionContext(TestContext.DataRow, (row)=> { //Test Logic goes here. } ); }

Note: You will have to do some tinkering with exceptions to get them to bubble correctly (you may have an aggregate exception here, you'll need the first exception from it).注意:您将不得不对异常进行一些修补以使它们正确冒泡(您可能在这里有一个聚合异常,您需要从中获得第一个异常)。 The amount of time displayed that each test takes to execute will no longer be accurate.显示的每个测试执行所需的时间将不再准确。 You will also want to cleanup the ParallelTesting class after the last row is completed.您还需要在最后一行完成后清理 ParallelTesting 类。

How it works: The test logic is wrapped in a lambda and passed to a static class that will execute the logic once for each row of test data when it is first called (first row executed).如何工作的:测试逻辑被包装在一个 lambda 中并传递给一个静态类,该类将在第一次调用(第一行执行)时为每行测试数据执行一次逻辑。 Successive calls to the static class simply wait for the prestarted test Task to finish.对静态类的连续调用只是等待预先启动的测试任务完成。

In this way each call the test framework made to the TestMethod simply collects the test results of the corresponding test that was already run.通过这种方式,测试框架对 TestMethod 所做的每次调用只是收集已经运行的相应测试的测试结果。

Possible Improvements:可能的改进:

  • Make AsyncExecutionContext take a maxSynchronousTasks parameter.使 AsyncExecutionContext 采用 maxSynchronousTasks 参数。
  • Look into how the framework moves complete stacktraces across unmanaged code to see if the Task.Exception can be passed to the visual studio test framework without rethrowing and destroying the stacktrace.查看框架如何跨非托管代码移动完整的堆栈跟踪,以查看是否可以将 Task.Exception 传递给 Visual Studio 测试框架,而无需重新抛出和破坏堆栈跟踪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM