如何在C# NUnit 3.6.1中让测试类内每个测试用例独立进程执行
没问题,我来帮你搞定这个NUnit并行测试的需求——既要让测试类内部的用例并行跑,还要每个测试都在独立进程里保证彻底隔离,同时适配你现有带共享字段的测试结构。
首先要给你的TestFixture加上Parallelizable特性,指定ParallelScope.Children,这样NUnit就知道可以并行执行这个类里的所有Test/TestCase方法。修改后的测试类头部应该是这样:
[TestFixture] [Parallelizable(ParallelScope.Children)] public class MyTestClass { // 你的原有代码... }
ParallelScope.Children的作用就是告诉NUnit:当前测试类的子元素(也就是各个测试方法)可以并行执行。
默认情况下NUnit是用线程级并行的,但你要的是每个测试用例跑在独立进程,这需要通过配置来开启。这里有两种方式:
方式1:用NUnit配置文件(推荐)
在你的测试项目里新建或修改nunit.runner.settings.xml文件,添加以下配置内容:
<NUnitProject> <Settings> <Parallelize> <WorkerCount>0</WorkerCount> <!-- 0表示自动根据CPU核心数分配进程数 --> <Scope>Children</Scope> </Parallelize> <TestAssembly> <ParallelizeAssembly>True</ParallelizeAssembly> <ProcessModel>Separate</ProcessModel> <!-- 核心配置:每个测试用例用独立进程 --> <DomainModel>Single</DomainModel> </TestAssembly> </Settings> </NUnitProject>
这里重点说下ProcessModel的取值:
Separate:每个测试用例都在单独的进程里执行,刚好符合你的需求SeparateByAssembly:每个测试程序集用一个进程,不符合你的要求InProcess:所有测试都在同一个进程里跑(默认值)
方式2:用命令行参数
如果习惯用命令行跑测试,可以在执行NUnit控制台命令时加上这些参数:
nunit3-console.exe YourTestAssembly.dll --process=Separate --workers=0 --parallel=children
--process=Separate就是指定每个测试用例使用独立进程的关键参数。
你现在的测试类里有_sut和_mockedDB这两个共享字段,好在进程级隔离会给每个测试创建一个全新的测试类实例,所以这些字段不会在不同测试间共享。不过为了更稳妥(比如以后如果切换回线程级并行),还有两个细节要修正:
补上TearDown特性
你原来的TearDownSUT方法没有加[TearDown]特性!NUnit不会自动执行这个清理方法,必须加上,否则资源无法正确释放:[TearDown] public void TearDownSUT() { _mockedDB = null; _sut = null; }可选:标记字段为ThreadStatic(兼容线程级并行)
如果以后可能切换回线程级并行,可以把共享字段标记为[ThreadStatic],确保每个线程拥有独立的字段实例:[ThreadStatic] private static MySUT _sut; [ThreadStatic] private static Mock<IDataBase> _mockedDB;当然,如果你只打算用进程级并行,这一步可以跳过,因为进程隔离已经足够保证字段独立。
跑测试的时候,你可以在测试方法里加一行代码打印当前进程ID,确认每个测试都在不同进程里执行:
[Test] public void MyFirstTC() { Console.WriteLine($"当前测试进程ID:{System.Diagnostics.Process.GetCurrentProcess().Id}"); // 原有测试逻辑... }
同时NUnit的控制台输出里也会显示类似“Running tests in parallel with X workers”的日志,说明并行已经生效。
- NUnit 3.6.1确实支持进程级并行,但如果有条件的话,建议升级到更近期的NUnit版本,后续版本对并行的稳定性和功能支持更完善。
- 进程级并行的开销比线程级大,因为每个进程启动都有资源消耗,如果你的测试数量非常多,要权衡隔离性和测试速度。
- 如果测试依赖外部资源(比如共享数据库、文件),即使进程隔离,也要确保每个测试使用独立的资源实例(比如临时数据库、专属测试文件),避免不同测试互相干扰。
内容的提问来源于stack exchange,提问作者RefMa77

