Mediatr: How to Mock - Moq

Created on 21 Jul 2015  路  16Comments  路  Source: jbogard/MediatR

I have a Request Handler that gets a IMediator injected via constructor injection (Autofac). The request handler under test conditionally calls other Send messages internally. I am trying to Mock the mediator injected using Moq and ensure that the send calls happen as expected. I am unable to find examples of how to do this. Can you provide and assistance or references as how to Mock the mediator to verify that the send call is made?

Thanks,
Brian

Most helpful comment

I dunno, I've never mocked the mediator.

All 16 comments

I dunno, I've never mocked the mediator.

@brianstanforth I think I understand what you're looking for. Here's one way to test that the Send method was called using Moq:

var fakeMediator = new Mock<IMediator>();
var fakedResult = new TestResult("blarg");
var mediator = new NestedMediator(fakeMediator.Object);

mediator.Send(new TestRequest());

fakeMediator.Verify(x => x.Send(It.IsAny<TestRequest>()));

Is this what you're looking to do? If not, can you share what you're trying, I have experience with both libraries. (Just never together)

@ChrisMissal That worked perfectly. Thanks for your help!

Any updated information on this? I'd like to Moq my Mediators on v8.0.0, and the handlers no longer have IMediatior as a parameter, so the above example does not apply.

Can you be more specific? Mocking mediator would mean the handlers would not be called (instead the mock would be) and the handlers have never had IMediator as a parameter.

So I followed this example on stackoverflow (https://stackoverflow.com/a/55443407/10171898) and the one above. In either one I need to pass the fakeMediator.Object - either to the Handler (1) or the NestedMediator (2) (which in my case is injected from the DI Services). This is where my confusion comes from, and why it looks like things has changed.

  1. Passing the fakeMediator.Object to the Handler does not work as it expects the DbContext and IConfigurationProvider.
    public Handler(ApplicationDbContext db, IConfigurationProvider configuration)
    Mocking these seem comprehensive, so I am fairly certain that is not the right approach.

  2. I have no idea on how to pass the fakeMediator.Object to the NestedMediator, or how to get it injected to my test.

I have no idea either - we don't mock MediatR in our tests.

I found a way to mock MediatR, when the nested mediator is not readily available. It is pretty simple actually, as I just use the mocked object with a setup that tells what is expected from a given query or command:

//Arrange
var mediator = new Mock<IMediator>();
mediator.Setup(m => m.Send(It.IsAny<QueryModel>(), It.IsAny<CancellationToken>())).ReturnsAsync(It.IsAny<ExpectedResultModel>());

//Act
await mediator.Object.Send(new QueryModel());

//Assert
mediator.Verify(x => x.Send(It.IsAny<QueryModel>(), It.IsAny<CancellationToken>()));

I found a way to mock MediatR, when the nested mediator is not readily available. It is pretty simple actually, as I just use the mocked object with a setup that tells what is expected from a given query or command:

//Arrange
var mediator = new Mock<IMediator>();
mediator.Setup(m => m.Send(It.IsAny<QueryModel>(), It.IsAny<CancellationToken>())).ReturnsAsync(It.IsAny<ExpectedResultModel>());

//Act
await mediator.Object.Send(new QueryModel());

//Assert
mediator.Verify(x => x.Send(It.IsAny<QueryModel>(), It.IsAny<CancellationToken>()));

But this doesn't actually mock the Handler, right? I tested it and it seems Ok but I'm not sure if this is a legit test case..

I believe this is ok as a unit test. If you dont use the mock you need to replicate the dbcontext along with other stuff, which can get complicated quickly. But it is true that this does not actually run your code per se.

I will look into if this can be improved upon, as i did notice these tests dont provide any code coverage which is something id like to improve :-)

I will comment here if/when i get to that :-)

Mocking the IMediator interface is only useful if you are unit testing the caller (most likely the controller for web projects). You can unit test handlers just as you would any other service with dependencies.

Jimmy tends to do more of integration tests where the code is run as it would be run in production (or as close to it) and even connects to the database to inject data and run tests. Unit testing is reserved for rich domain models in his projects.

here is a great video from one of his talks if you want more deets https://www.youtube.com/watch?v=v4jrYMsYSco

Mocking the IMediator interface is only useful if you are unit testing the caller (most likely the controller for web projects). You can unit test handlers just as you would any other service with dependencies.

It is possible in this case to test handlers for validation exceptions (becasue now validators are strictly related with invoking Mediator.Send method as one element of a behaviour pipeline)? Or unit testing is pointless in case of using CQRS/MediatR and better option is to just create integration tests ?

Unit testing isn't pointless but if your pipeline consists of complex business logic and validation then when unit testing the handlers alone you would have to assume that is in place and only unit test with valid data. The validators can be unit tested themselves, but this is definitely why integration tests on the whole pipeline can be easier.

I've mocked it out OK, decided to use a callback on my test to record the command that was sent so that I can test the values sent by the sender of the command are what I expected....

mockMediator.Setup(x => x.Send(It.IsAny>(), It.IsAny()))
.Callback, CancellationToken>((req, token) => commandSent = req as MyCommand)
.Returns(() => Task.FromResult(true));

Obviously you'd have to tweak that a bit and you could ditch the call back entirely if you didn't want it, or use verify

Was this page helpful?
0 / 5 - 0 ratings