rebus

How do I unit test Rebus handlers IFailed<Message> handle when secondLevelRetriesEnabled is enabled


I am in the process of writing some unit tests for my Rebus Handlers. I have opted to enable secondLevelRetriesEnabled which results in an IFailed<TMessage> being published when an exception is thrown in the Handler.

My Handler class definition is:

Handler<T> : IHandleMessages<T>, IHandleMessages<IFailed<T>>

When I run the process everything works as expected; the difficulty comes when attempting to write a unit test for the secondLevelRetriesEnabled behaviour.

When my unit test calls the IFailed<TMessage> method of my Handler which results in a call to await bus.Advanced.TransportMessage.Deadletter(message) I get the following exception from the FakeBus.

"Attempted to dead-letter the current message using error details 'Failed to handle message after 2 deferrals', but no message context could be found! This is probably a sign that this method was called OUTSIDE of a Rebus handler, or on a separate, disconnected thread somehow. Please only call this method inside Rebus handlers."

Can someone point me in the right direction to resolve the Deadletter queue exception when testing the IFailed message handle. As far as I can see there is no HandleFixture like the SagaFixture which supports fixture.DeliverFailed(new OrdinaryMessage(...), new ApplicationException("oh no"));


Solution

  • I don't think there's a really elegant way at the moment, but one way that you could wrap up and maybe make pretty yourself, is to do something like this:

    // this is the message we're pretending to be handling
    var transportMessage = new TransportMessage(...);
    
    using var scope = new RebusTransactionScope();
    
    var transactionContext = scope.TransactionContext;
    var incomingStepContext = new IncomingStepContext(transportMessage, transactionContext);
    
    // fake incoming step context here:
    transactionContext.Items[StepContext.StepContextKey] = incomingStepContext;
    
    // now MessageContext.Current should return a proper IMessageContext
    
    //< exercise your handler here
    
    //< check incomingStepContext here
    

    This is clearly something that could be better, so feel free to raise an issue in the Rebus.TestHelpers repository, which would be the right place to live for some kind of solution to this problem.