如何在NUnit中为TestContainers配置全局OneTimeSetup和OneTimeTearDown?
在NUnit中实现TestContainers MongoDB容器全局复用
问题场景
我在.NET测试中尝试结合TestContainers与NUnit使用,现有两个测试用例,每个测试都会重复创建、启动MongoDB容器,用完后销毁,总执行时间约9秒。这些测试均继承自一个基类,基类通过OneTimeSetUp和OneTimeTearDown管理容器生命周期:
[OneTimeSetUp] public async Task OneTimeSetup() { _testContainer = new MongoDbBuilder().Build(); await _testContainer.StartAsync(); _client = new MongoClient(_testContainer.GetConnectionString()); Database = _client.GetDatabase("test"); } [OneTimeTearDown] public async Task OneTimeTeardown() => await _testContainer.DisposeAsync();
当前每个测试类都会重复执行容器的创建和销毁逻辑,我希望实现全局复用容器的执行流程:
Global Setup <==== 在此启动容器 Test1 Setup <---- 使用已创建的容器 Test1 Run Test1 Teardown Test2 Setup <---- 使用同一容器 Test2 Run Test2 Teardown Global Teardown <==== 在此销毁容器
请问能否通过NUnit实现该需求?
解决方案:用NUnit的[SetUpFixture]实现全局容器生命周期管理
当然可以实现,核心是使用NUnit的[SetUpFixture]特性定义全局初始化和清理逻辑,替代原基类中每个测试类执行一次的OneTimeSetUp/OneTimeTearDown。
步骤1:创建全局SetUpFixture类
在测试项目的根命名空间下创建一个标记[SetUpFixture]的类,统一管理MongoDB容器的全局生命周期:
using NUnit.Framework; using TestContainers.MongoDb; using MongoDB.Driver; [SetUpFixture] public class GlobalTestSetup { public static MongoDbContainer? TestContainer { get; private set; } public static IMongoDatabase? TestDatabase { get; private set; } [OneTimeSetUp] public async Task GlobalSetup() { // 全局启动一次MongoDB容器 TestContainer = new MongoDbBuilder().Build(); await TestContainer.StartAsync(); var client = new MongoClient(TestContainer.GetConnectionString()); TestDatabase = client.GetDatabase("test"); } [OneTimeTearDown] public async Task GlobalTeardown() { // 全局销毁一次容器 if (TestContainer != null) { await TestContainer.DisposeAsync(); } } }
步骤2:修改测试基类
原测试基类无需再管理容器生命周期,直接引用全局类的静态属性即可,同时可在[SetUp]中清理集合数据保证测试隔离:
using NUnit.Framework; using MongoDB.Driver; public class MongoTestBase { protected IMongoDatabase Database => GlobalTestSetup.TestDatabase!; [SetUp] public void TestSetup() { // 每个测试前清理集合,避免测试间数据污染 foreach (var collectionName in Database.ListCollectionNames().ToList()) { Database.DropCollection(collectionName); } } }
步骤3:编写测试类
测试类只需继承基类,正常编写测试逻辑即可,无需关心容器的创建与销毁:
using NUnit.Framework; using MongoDB.Driver; [TestFixture] public class FirstMongoTests : MongoTestBase { [Test] public async Task Test1_InsertDocument() { var collection = Database.GetCollection<MyDocument>("docs"); await collection.InsertOneAsync(new MyDocument { Name = "Test1" }); var count = await collection.CountDocumentsAsync(_ => true); Assert.That(count, Is.EqualTo(1)); } } [TestFixture] public class SecondMongoTests : MongoTestBase { [Test] public async Task Test2_QueryDocument() { var collection = Database.GetCollection<MyDocument>("docs"); await collection.InsertOneAsync(new MyDocument { Name = "Test2" }); var doc = await collection.Find(_ => _.Name == "Test2").FirstOrDefaultAsync(); Assert.That(doc, Is.Not.Null); } } public class MyDocument { public string Name { get; set; } = string.Empty; }
关键说明
[SetUpFixture]的OneTimeSetUp会在所有测试开始前执行一次,OneTimeTearDown会在所有测试结束后执行一次,完全匹配全局容器的生命周期需求。- 每个测试前的
[SetUp]清理集合数据,能保证测试用例之间的独立性,避免数据互相干扰。 - 整个测试套件仅会启动和销毁一次MongoDB容器,可大幅缩短总执行时间。
内容的提问来源于stack exchange,提问作者napfernandes
相关产品推荐
相关产品推荐

