Mocking calls of MassTransit's ISendEndpointProvider Send method
Background
MassTransit allows you to produce messages using two different methods:
- You can send a message (commands) using ISendEndpointProvider interface.
- You can publish a message (events) using IPublishEndpoint interface.
Tackling the message sending
Basically, when you send a message, you must specify an endpoint. If a specific message is designed to be sent only to one endpoint, it does not make sense to specify the URL every time. MassTransit comes to help and provides us the ability to create EndpointConventions.
EndpointConvention.Map<CreateUser>(new Uri(serviceAddress1));
EndpointConvention.Map<DeleteBook>(new Uri(serviceAddress2));
EndpointConvention.Map<UpdateInventory>(new Uri(serviceAddress3));
This allows us to specify the endpoints of our message only once.
Peeking into ISendEndpointProvide interface
As you can see in the picture, ISendEndpointProvider contains only a method which asks for an endpoint address. If it does not provide us the ability to skip giving the endpoint address every time we send a message, why are we bothering with the EndpointConventions?
Extension Methods to the rescue
EndpointConventionExtensions contains extensions methods for ISendEndpointProvider interface.
We can see that it tries to fetch the endpoint convention based on the type of your message. After it got the endpoint, it retrieves an implementation of ISendEndpoint by calling ISendEndpintProvider.GetSendEndpoint.
This is the most important thing to note:
To send a message, an implementation of ISendEndpoint is needed. In order to receive it, a call to ISendEndpointProvider.GetSendEndpoint is necessary.
What are we trying to test?
Suppose we want to test a method which sends a message through ISendEndpointProvider. For the sake of simplicity, let's take the following code as example:
public class YourService : IYourService
{
private readonly ISendEndpointProvider sendEndpointProvider;
public YourService(ISendEndpointProvider sendEndpointProvider)
{
this.sendEndpointProvider = this.sendEndpointProvider;
}
public async Task MethodWhichSendsMessages()
{
await sendEndpointProvider.Send(new TestMessage
{
Message = "random message"
});
}
}
Wrapping it up
This is how you can mock calls or verify if Send
method is called on the ISendEndpointProvider
:
public class YourServiceTests
{
private readonly IYourService yourService;
private readonly Mock<ISendEndpoint> mockSendEndpoint;
public YourServiceTests()
{
EndpointConvention.Map<TestMessage>(new Uri("http://random"));
mockSendEndpoint = new Mock<ISendEndpoint>();
var mockSendEndpointProvider = new Mock<ISendEndpointProvider>();
mockSendEndpointProvider.Setup(x => x.GetSendEndpoint(It.IsAny<Uri>())).Returns(Task.FromResult(mockSendEndpoint.Object));
yourService = new YourService(mockSendEndpointProvider.Object);
}
[Fact]
public async Task MethodWhichSendsMessages_Works()
{
//Act
await yourService.MethodWhichSendsMessages();
//Assert
mockSendEndpoint.Verify(x => x.Send(It.IsAny<YourMessage>(), It.IsAny<CancellationToken>()), Times.Once);
}
}