单元测试中使用内存版MassTransit无法发送消息如何解决?
问题原因
你遇到的ObjectDisposedException核心是测试方法执行速度远快于消息异步消费速度:
- 调用
await bus.Publish()仅完成了消息发送,没有等待消费者执行完成 - 测试方法在Publish完成后直接退出,
WebApplicationFactory关联的服务容器会被立即销毁 - 此时MassTransit还在异步触发消费者逻辑,需要从已经被销毁的
IServiceProvider中解析消费者实例,就抛出了对象已释放异常
修复方案
方案1:等待总线空闲(适配现有代码改动最小)
修改测试方法,发布消息后调用IBusControl的WaitForInactivityAsync方法,等待所有消息消费完成再退出测试:
[Fact] public async Task SendMassTransitMessage() { var client = _factory.CreateClient(); // IBusControl是单例服务,直接从根容器获取即可,不需要自行创建Scope var busControl = _factory.Services.GetRequiredService<IBusControl>(); await busControl.Publish(new Message {Text = "Test message from test"}); // 等待总线所有消息消费完成,超时时间可根据实际场景调整 await busControl.WaitForInactivityAsync(TimeSpan.FromSeconds(5)); }
方案2:使用MassTransit官方测试套件(更规范的单元测试写法)
如果是专门针对消息消费逻辑的单元测试,可以使用MassTransit官方提供的测试Harness,更精准地控制消费等待逻辑、做消费断言:
- 首先NuGet安装
MassTransit.Testing包 - 测试代码示例:
[Fact] public async Task SendMassTransitMessage() { await using var provider = new ServiceCollection() .AddMassTransitTestHarness(x => { x.AddConsumer<MessageConsumer>(); }) .BuildServiceProvider(true); var harness = provider.GetRequiredService<ITestHarness>(); await harness.Start(); try { await harness.Bus.Publish(new Message {Text = "Test message from test"}); // 断言消息已被消费 Assert.True(await harness.Consumed.Any<Message>()); // 也可精准断言指定消费者消费了消息 var consumerHarness = harness.GetConsumerHarness<MessageConsumer>(); Assert.True(await consumerHarness.Consumed.Any<Message>()); } finally { await harness.Stop(); } }
额外说明
如果需要保留WebApplicationFactory的完整上下文测试(比如同时测试API接口和消息消费链路),也可以直接在WebApplicationFactory的服务配置中注入测试Harness,不需要单独初始化服务容器。
内容的提问来源于stack exchange,提问作者Niels Heirbaut
相关产品推荐
相关产品推荐

