【发布时间】:2016-04-05 08:36:22
【问题描述】:
我目前正在重构一个程序以使用 Membus 消息总线进行事件聚合,并且此消息总线允许我通过返回可以订阅的 IObservable 实例来“观察”总线上的事件到。
在我的单元测试中,我想确保我的组件只在适当的时候在总线上发布特定的消息。我尝试这样做的方法是在我的测试规范类中包含以下类型的设置逻辑:
private readonly IBus messageBus;
private readonly IObservable<Model> myObservable;
public ComponentModelGatewaySpec()
{
messageBus = TestHelper.DefaultMessageBus;
myObservable = messageBus.Observe<ModelPublishedEventMessage>().Select(it => it.Model);
}
然后在一个测试用例中,我想做如下的事情:
public async Task Only_Publish_Incomplete_Models_After_Receiving_Request()
{
var defaultTimeout = TimeSpan.FromMilliseconds(1000);
// GIVEN a component model gateway and an incomplete model update.
var modelUpdate = new Model { IntProperty = 1, BoolProperty = null };
Assert.False(modelUpdate.IsComplete);
var gateway = MockComponentModelGateway;
gateway.SetMessageBus(messageBus);
// EXPECT no current model is published after publishing the incomplete model update.
Task<bool> noModelPublished = myObservable.WithinWindow(defaultTimeout).NoEmissionsOccurred().ToTask();
messageBus.Publish(new ModelUpdateEventMessage(modelUpdate));
Assert.True(await noModelPublished);
// WHEN we publish a current model query.
Task<Model> publishedModel = myObservable.WithinWindow(defaultTimeout).FirstAsync().ToTask();
messageBus.Publish(new ModelQueryRequestedEventMessage());
// THEN the model should be published.
Assert.Equal(modelUpdate, await publishedModel);
}
我主要追求的是一种测试方式:
- “在我表演后没有发布此特定类型的事件 这(一系列)行动,至少在 X 时间内。”
- “在我执行此(一系列)操作后发布了此特定类型的事件,这就是我期望该事件的属性。”
我希望能够异步处理所有这些逻辑,否则我会有一堆测试用例最终阻塞 1 秒或更长时间。
也许可以为此使用Timeout,但Timeout 会导致在超时时引发异常,这似乎是我期望它们被抛出时处理事情的一种笨拙的方式。我确实在可观察的组合中使用Timeout,但仅在发生超时意味着测试应该失败的情况下。
目前,我正在尝试使用 Window、Buffer、FirstAsync 等的各种组合来完成此操作,但在所有测试用例中都没有得到我期望的行为。
编辑
我已经添加了自己的解决方案,但我将其视为临时措施,直到我能够采纳 Lee Campbell 的建议(请参阅下面的答案)。
【问题讨论】:
-
看看 TestScheduler 和 ReactiveTest 基类。你可以使用这些来做你想做的事情并控制时间和并发性。
-
@user630190 感谢您指出这一点,我回家后会查看的。我找到了另一个我目前正在尝试的解决方案,它似乎对我有用。
标签: c# unit-testing system.reactive reactive-programming