如何测试MassTransit状态机忽略消息?优化单测执行效率方案求助
在MassTransit Saga状态机中测试事件忽略逻辑的优化方案
解决首个测试预热超时问题
单独运行首个测试时,MassTransit测试Harness的初始化预热耗时会导致超时失败,可利用NUnit的OneTimeSetUp在测试类启动前完成全局预热,避免每个测试重复初始化开销:
[TestFixture] public class YourSagaTests { private InMemoryTestHarness _testHarness; private ISagaStateMachineTestHarness<YourSagaInstance, YourSagaStateMachine> _sagaHarness; private YourSagaStateMachine _machine; [OneTimeSetUp] public async Task OneTimeSetUp() { // 初始化临时Harness触发MassTransit类型预热 var tempHarness = new InMemoryTestHarness(); _machine = new YourSagaStateMachine(); tempHarness.StateMachineSaga(_machine, InMemorySagaRepository<YourSagaInstance>.Factory); await tempHarness.Start(); // 发布空事件触发总线初始化 await tempHarness.Bus.Publish(new DummyWarmupEvent()); await Task.Delay(300); // 给足初始化时间 await tempHarness.Stop(); } [SetUp] public async Task SetUp() { // 每个测试创建干净的Harness实例 _testHarness = new InMemoryTestHarness(); _sagaHarness = _testHarness.StateMachineSaga(_machine, InMemorySagaRepository<YourSagaInstance>.Factory); await _testHarness.Start(); } [TearDown] public async Task TearDown() { await _testHarness.Stop(); } // 测试方法... } // 用于预热的空事件类型 public class DummyWarmupEvent { }
实现忽略事件时发布Ignored<T>消息
MassTransit的Ignore()配置本身不会触发额外行为,但可以通过链式调用Then()在忽略事件的同时发布自定义的Ignored<T>消息,让测试走快速通过路径:
1. 定义通用忽略标记消息
public class Ignored<T> where T : class { }
2. 在状态机中配置忽略逻辑+发布标记消息
在状态配置中,为需要忽略的事件添加发布Ignored<T>的行为:
public class YourSagaStateMachine : MassTransitStateMachine<YourSagaInstance> { public YourSagaStateMachine() { InstanceState(x => x.CurrentState); // 定义事件 Event(() => AnswerSetAutosaved, x => x.CorrelateById(m => m.Message.AnswerSetId)); // Draft状态下忽略事件并发布标记消息 During(Draft, Ignore(AnswerSetAutosaved) .Then(context => context.Publish(new Ignored<AnswerSetAutosaved>()))); // 其他状态与事件配置... } public State Draft { get; private set; } public Event<AnswerSetAutosaved> AnswerSetAutosaved { get; private set; } }
3. 封装扩展方法简化重复配置(可选)
如果多个事件需要相同逻辑,封装扩展方法减少代码重复:
public static class StateMachineExtensions { public static EventActivityBinder<TInstance, TEvent> IgnoreAndPublishIgnored<TInstance, TEvent>( this EventActivityBinder<TInstance, TEvent> binder) where TInstance : class, SagaStateMachineInstance where TEvent : class { return binder.Ignore() .Then(context => context.Publish(new Ignored<TEvent>())); } }
使用时只需替换为:
During(Draft, IgnoreAndPublishIgnored(AnswerSetAutosaved));
4. 优化后的测试代码
现在测试可以直接监听Ignored<T>消息,无需等待超时,快速验证事件被忽略:
[Test] public async Task When_AnswerSetAutoSaved_And_StateIsDraft_Should_Ignore() { var instance = await CreateInstanceInState(_machine.Draft); var answerSetId = instance.CorrelationId; var formPackageInstanceId = instance.FormPackageInstanceId; await _testHarness.Bus.Publish(new AnswerSetAutosaved { AnswerSetId = answerSetId, FormPackageInstanceId = formPackageInstanceId, }); // 验证Saga收到了事件 Assert.That(await _sagaHarness.Consumed.Any<AnswerSetAutosaved>()); // 验证发布了忽略标记消息(快速通过) Assert.That(await _testHarness.Published.Any<Ignored<AnswerSetAutosaved>>()); // 确保没有发布错误消息 Assert.That(await _testHarness.Published.Any<Fault<AnswerSetAutosaved>>(), Is.False); }
内容的提问来源于stack exchange,提问作者Arvid Inge
相关产品推荐
相关产品推荐

