I have a program that I'm currently refactoring to use the Membus message bus for event aggregation, and this message bus allows me to "observe" events on the bus by returning instances of IObservable that I can subscribe to.
In my unit tests, I want to ensure that my components only publish particular messages on the bus when it's appropriate. The way I've tried to do this is by including the following sort of setup logic in my test specification classes:
private readonly IBus messageBus;
private readonly IObservable<Model> myObservable;
public ComponentModelGatewaySpec()
{
messageBus = TestHelper.DefaultMessageBus;
myObservable = messageBus.Observe<ModelPublishedEventMessage>().Select(it => it.Model);
}
Then in a test case, I'd like to do something like the following:
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);
}
What I'm essentially after is a way of testing either:
- "No events of this particular type were published after I performed this (series of) action(s), at least within X amount of time."
- "An event of this particular type was published after I performed this (series of) action(s), and this is what I expect the properties of that event to be."
I'd like to be able to handle all this logic asynchronously, or else I'll have a bunch of test cases that end up blocking for 1 or more seconds.
It may be possible to use Timeout for this, but Timeout causes an exception to be thrown on timeouts which seems like a cludgy way of handling things when I'm expecting them to be thrown. I do use Timeout in observable compositions, but only in cases where a timeout occurring means the test should fail.
Currently, I'm trying to use various combinations of Window, Buffer, FirstAsync, etc. to accomplish this but I'm not getting the behaviour I expect in all of my test cases.
Aucun commentaire:
Enregistrer un commentaire