C# 串行执行单元测试(而不是并行)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1408175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute unit tests serially (rather than in parallel)
提问by jrista
I am attempting to unit test a WCF host management engine that I have written. The engine basically creates ServiceHost instances on the fly based on configuration. This allows us to dynamically reconfigure which services are available without having to bring all of them down and restart them whenever a new service is added or an old one is removed.
我正在尝试对我编写的 WCF 主机管理引擎进行单元测试。该引擎基本上根据配置动态创建 ServiceHost 实例。这允许我们动态地重新配置哪些服务可用,而不必在添加新服务或删除旧服务时将所有服务关闭并重新启动它们。
I have run into a difficulty in unit testing this host management engine, however, due to the way ServiceHost works. If a ServiceHost has already been created, opened, and not yet closed for a particular endpoint, another ServiceHost for the same endpoint can not be created, resulting in an exception. Because of the fact that modern unit testing platforms parallelize their test execution, I have no effective way to unit test this piece of code.
但是,由于 ServiceHost 的工作方式,我在对这个主机管理引擎进行单元测试时遇到了困难。如果已为特定端点创建、打开且尚未关闭 ServiceHost,则无法为同一端点创建另一个 ServiceHost,从而导致异常。由于现代单元测试平台并行执行它们的测试这一事实,我没有有效的方法来对这段代码进行单元测试。
I have used xUnit.NET, hoping that because of its extensibility, I could find a way to force it to run the tests serially. However, I have not had any luck. I am hoping that someone here on SO has encountered a similar issue and knows how to get unit tests to run serially.
我使用过 xUnit.NET,希望由于它的可扩展性,我可以找到一种方法来强制它连续运行测试。但是,我没有任何运气。我希望 SO 上的某个人遇到了类似的问题,并且知道如何让单元测试串行运行。
NOTE: ServiceHostis a WCF class, written by Microsoft. I don't have the ability to change it's behavior. Hosting each service endpoint only once is also the proper behavior...however, it is not particularly conducive to unit testing.
注意:ServiceHost是一个 WCF 类,由 Microsoft 编写。我没有能力改变它的行为。仅托管每个服务端点一次也是正确的行为......但是,它不是特别有利于单元测试。
回答by TrueWill
I don't know the details, but it sounds like you might be trying to do integration testingrather than unit testing. If you could isolate the dependency on ServiceHost
, that would likely make your testing easier (and faster). So (for instance) you might test the following independently:
我不知道细节,但听起来您可能正在尝试进行集成测试而不是单元测试。如果您可以隔离对 的依赖ServiceHost
,那可能会使您的测试更容易(更快)。因此(例如)您可以独立测试以下内容:
- Configuration reading class
- ServiceHost factory (possibly as an integration test)
- Engine class that takes an
IServiceHostFactory
and anIConfiguration
- 配置阅读类
- ServiceHost 工厂(可能作为集成测试)
- 带有一个
IServiceHostFactory
和一个的引擎类IConfiguration
Tools that would help include isolation (mocking) frameworks and (optionally) IoC container frameworks. See:
有助于包括隔离(模拟)框架和(可选)IoC 容器框架的工具。看:
回答by Graviton
Maybe you can use Advanced Unit Testing. It allows you to define the sequence in which you run the test. So you may have to create a new cs file to host those tests.
也许您可以使用Advanced Unit Testing。它允许您定义运行测试的顺序。因此,您可能需要创建一个新的 cs 文件来托管这些测试。
Here's how you can bend the test methods to work in the sequence you want.
以下是如何改变测试方法以按所需顺序工作的方法。
[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.");
...
}
Do let me know whether it works.
请让我知道它是否有效。
回答by HB MAAM
you can Use Playlist
你可以使用播放列表
right click on the test method -> Add to playlist -> New playlist
右键单击测试方法 -> 添加到播放列表 -> 新建播放列表
then you can specify the execution order, the default is, as you add them to the play list but you can change the playlist file as you want
然后您可以指定执行顺序,默认为,将它们添加到播放列表中,但您可以根据需要更改播放列表文件
回答by Squiggle
As stated above, all good unit tests should be 100% isolated. Using shared state (e.g. depending on a static
property that is modified by each test) is regarded as bad practice.
如上所述,所有好的单元测试都应该是 100% 隔离的。使用共享状态(例如,取决于static
每个测试修改的属性)被认为是不好的做法。
Having said that, your question about running xUnit tests in sequence does have an answer! I encountered exactly the same issue because my system uses a static service locator (which is less than ideal).
话虽如此,您关于按顺序运行 xUnit 测试的问题确实有答案!我遇到了完全相同的问题,因为我的系统使用静态服务定位器(不太理想)。
By default xUnit 2.x runs all tests in parallel. This can be modified per-assembly by defining the CollectionBehavior
in your AssemblyInfo.cs in your test project.
默认情况下,xUnit 2.x 并行运行所有测试。这可以通过CollectionBehavior
在测试项目的 AssemblyInfo.cs 中定义每个程序集来修改。
For per-assembly separation use:
对于每个组件分离使用:
using Xunit;
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
or for no parallelization at all use:
或者根本不使用并行化:
[assembly: CollectionBehavior(DisableTestParallelization = true)]
The latter is probably the one you want. More information about parallelisation and configuration can be found on the xUnit documentation.
后者可能是您想要的。有关并行化和配置的更多信息可以在xUnit 文档中找到。
回答by Dmitry Polomoshnov
For .NET Core projects, create xunit.runner.json
with:
对于 .NET Core 项目,创建xunit.runner.json
:
{
"parallelizeAssembly": false,
"parallelizeTestCollections": false
}
Also, your csproj
should contain
此外,你csproj
应该包含
<ItemGroup>
<None Update="xunit.runner.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
For old .Net Core projects, your project.json
should contain
对于旧的 .Net Core 项目,您project.json
应该包含
"buildOptions": {
"copyToOutput": {
"include": [ "xunit.runner.json" ]
}
}
回答by Mark Amery
For .NET Core projects, you can configure xUnit with an xunit.runner.json
file, as documented at https://xunit.github.io/docs/configuring-with-json.html.
对于 .NET Core 项目,您可以使用xunit.runner.json
文件配置 xUnit ,如https://xunit.github.io/docs/configuring-with-json.html 中所述。
The setting you need to change to stop parallel test execution is parallelizeTestCollections
, which defaults to true
:
您需要更改以停止并行测试执行的设置是parallelizeTestCollections
,默认为true
:
Set this to
true
if the assembly is willing to run tests inside this assembly in parallel against each other. ... Set this tofalse
to disable all parallelization within this test assembly.JSON schema type: boolean
Default value:true
true
如果程序集愿意在此程序集中彼此并行运行测试,则将此设置为。... 将此设置false
为禁用此测试程序集中的所有并行化。JSON 模式类型:boolean
默认值:true
So a minimal xunit.runner.json
for this purpose looks like
所以xunit.runner.json
这个目的的最小看起来像
{
"parallelizeTestCollections": false
}
As noted in the docs, remember to include this file in your build, either by:
如文档中所述,请记住通过以下方式将此文件包含在您的构建中:
- Setting Copy to Output Directoryto Copy if newerin the file's Propertiesin Visual Studio, or
Adding
<Content Include=".\xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content>
to your
.csproj
file, orAdding
"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
to your
project.json
file
- 如果在 Visual Studio中的文件属性中较新,则将复制到输出目录设置为复制,或
添加
<Content Include=".\xunit.runner.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content>
到您的
.csproj
文件,或添加
"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
到你的
project.json
文件
depending upon your project type.
取决于您的项目类型。
Finally, in additionto the above, if you're using Visual Studio then make sure that you haven't accidentally clicked the Run Tests In Parallelbutton, which will cause tests to run in parallel even if you've turned off parallelisation in xunit.runner.json
. Microsoft's UI designers have cunningly made this button unlabelled, hard to notice, and about a centimetre away from the "Run All"button in Test Explorer, just to maximise the chance that you'll hit it by mistake and have no idea why your tests are suddenly failing:
最后,除上述之外,如果您使用的是 Visual Studio,请确保您没有意外单击“并行运行测试”按钮,这将导致测试并行运行,即使您已关闭xunit.runner.json
. 微软的 UI 设计人员巧妙地将这个按钮设置为未标记、难以注意到,并且距离测试资源管理器中的“全部运行”按钮大约一厘米,只是为了最大限度地增加你误触它的机会并且不知道为什么你的测试突然失败:
回答by Abhinav Saxena
Each test class is a unique test collection and tests under it will run in sequence, so if you put all of your tests in same collection then it will run sequentially.
每个测试类都是一个独特的测试集合,它下的测试将按顺序运行,因此如果您将所有测试放在同一个集合中,那么它将按顺序运行。
In xUnit you can make following changes to achieve this:
在 xUnit 中,您可以进行以下更改以实现此目的:
Following will run in parallel:
以下将并行运行:
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");
}
}
}
To make it sequential you just need to put both the test classes under same collection:
要使其连续,您只需要将两个测试类放在同一个集合中:
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");
}
}
}
For more info you can refer to this link
有关更多信息,您可以参考此链接
回答by Matías Romero
I've added the attribute [Collection("Sequential")]in a base class:
我在基类中添加了属性[Collection("Sequential")]:
namespace IntegrationTests
{
[Collection("Sequential")]
public class SequentialTest : IDisposable
...
public class TestClass1 : SequentialTest
{
...
}
public class TestClass2 : SequentialTest
{
...
}
}
回答by Gündüz Emre ?ZER
This is old question but I wanted to write a solution to people searching newly like me :)
这是一个老问题,但我想为像我这样新搜索的人写一个解决方案:)
Note:I use this method in Dot Net Core WebUI integration tests with xunit version 2.4.1.
注意:我在使用 xunit 版本 2.4.1 的 Dot Net Core WebUI 集成测试中使用此方法。
Create an empty class named NonParallelCollectionDefinitionClass and then give CollectionDefinition attribute to this class as below. (The important part is DisableParallelization = true setting.)
创建一个名为 NonParallelCollectionDefinitionClass 的空类,然后将 CollectionDefinition 属性赋予该类,如下所示。(重要的部分是 DisableParallelization = true 设置。)
using Xunit;
namespace WebUI.IntegrationTests.Common
{
[CollectionDefinition("Non-Parallel Collection", DisableParallelization = true)]
public class NonParallelCollectionDefinitionClass
{
}
}
After then add Collection attribute to the class which you don't want it to run in parallel as below. (The important part is name of collection. It must be same with name used in CollectionDefinition)
然后将 Collection 属性添加到您不希望它并行运行的类,如下所示。(重要的部分是集合的名称。它必须与 CollectionDefinition 中使用的名称相同)
namespace WebUI.IntegrationTests.Controllers.Users
{
[Collection("Non-Parallel Collection")]
public class ChangePassword : IClassFixture<CustomWebApplicationFactory<Startup>>
...
When we do this, firstly other parallel tests run. After that the other tests which has Collection("Non-Parallel Collection") attribute run.
当我们这样做时,首先运行其他并行测试。之后运行具有 Collection("Non-Parallel Collection") 属性的其他测试。
回答by Matt Hayes
None of the suggested answers so far worked for me. I have a dotnet core app with XUnit 2.4.1. I achieved the desired behavior with a workaround by putting a lock in each unit test instead. In my case, I didn't care about running order, just that tests were sequential.
到目前为止,没有一个建议的答案对我有用。我有一个带有 XUnit 2.4.1 的 dotnet 核心应用程序。我通过在每个单元测试中加锁来实现了所需的行为。就我而言,我不关心运行顺序,只关心测试是顺序的。
public class TestClass
{
[Fact]
void Test1()
{
lock (this)
{
//Test Code
}
}
[Fact]
void Test2()
{
lock (this)
{
//Test Code
}
}
}