I want to unit test my MassTransit consumer which does not send a response back. Currently my test does seem to be publishing a message, but the consumer is not being triggered, so my breakpoints are not getting hit within it at all.
The consumer is fairly straight forward, but it does have a service injected via DI.
public class BudgetExceededConsumer : IConsumer<IBudgetExceeded>
{
private readonly INotificationHubService _notificationHubService;
public BudgetExceededConsumer(INotificationHubService notificationHubService)
{
_notificationHubService = notificationHubService;
}
public async Task Consume(ConsumeContext<IBudgetExceeded> context)
{
try
{
var message = context.Message;
await _notificationHubService.SendNotificationAsync(context.Message);
}
catch (Exception ex)
{
throw new Exception("Failed to send push notification for exceeding budget usage", ex);
}
}
}
The consumer is added to my Azure function using the following:
builder.Services.AddMassTransitForAzureFunctions(cfg =>
{
cfg.AddConsumersFromNamespaceContaining<ConsumerNamespace>();
});
And I have a relatively straightforward service that is used by other functions to send the messages:
private readonly ISendEndpointProvider _sendEndpoint;
public MessagingService(ISendEndpointProvider sendEndpoint)
{
_sendEndpoint = sendEndpoint;
}
public async Task SendMessage<T>(string queueName, object messageBody) where T : class, MessageBase
{
var endpoint = await _sendEndpoint.GetSendEndpoint(new Uri($"queue:{queueName}"));
await endpoint.Send<T>(messageBody);
}
I would like to write a simple test for the consumer so I could mock the service and then verify that the mocked service is being called. However I cannot get to the point of running a test and my consumer being hit by a breakpoint. I am not setting up the service injected into the consumer anywhere in the DI. Currently it is not complaining about that which makes me think I am missing something in the setup.
public async Task Budget_message_gets_consumed()
{
await using var provider = new ServiceCollection()
.AddMassTransitInMemoryTestHarness(cfg =>
{
cfg.AddConsumer<BudgetExceededConsumer>();
cfg.AddConsumerTestHarness<BudgetExceededConsumer>();
})
.BuildServiceProvider(true);
var harness = provider.GetRequiredService<InMemoryTestHarness>();
await harness.Start();
try
{
var bus = provider.GetRequiredService<IBus>();
BudgetExceededMessage message = new BudgetExceededMessage
{
UserEmailAddress = "[email protected]",
Budget = "£20.00",
TotalSpend = "£23.56"
};
await bus.Publish(message);
var result = await harness.Consumed.Any<IBudgetExceeded>();
Assert.That(result, Is.True); //This is true
var consumerHarness = provider.GetRequiredService<IConsumerTestHarness<BudgetExceededConsumer>>();
var result2 = await consumerHarness.Consumed.Any<IBudgetExceeded>();
Assert.That(result2, Is.True); //This is FALSE.
}
finally
{
await harness.Stop();
await provider.DisposeAsync();
}
}
As you can see the second Assert is false. I think if this was true then I would be seeing the breakpoint in my consumer getting hit.
Is there part of the setup here I need to change so the second assert will get evaluated correctly? I know my setup is slightly different to the docs since I am not using the approach that gives a response.
Thanks
consumerHarness.Consumed.Any<>()
is returning false. If I test the code manually, everything works fine. Taking your comment into account, I removed all dependencies in the constructor and body (leaving onlyConsole.WriteLine
) and still observing the same. I have a static constructor on my consumer class with aConsole.WriteLine
and it simply doesn't get hit so I'm thinking the message is being sent (first assert works), but not delivered (second assert fails). – Lading