How to instantiate Mediatr as part of a Unit Test?

Roland picture Roland · Mar 31, 2019 · Viewed 11.5k times · Source

I am trying to build an xUnit Test project for an MVC Core 2.2 Application that is based on the CQRS/ES pattern. I utilize MediatR as part of my CQRS/ES pattern in the MVC application.

In one of my commands which I would like to test, I inject MediatR to publish an event once a customer record has been updated. Kind of like this:

    public class UpdateCustomerCommandHandler : IRequestHandler<UpdateCustomerCommand>
    {
        public IMediator Mediator { get; set;  }

        public UpdateCustomerCommandHandler(IMediator mediator)
        {
            Mediator = mediator;
        }

        public Task<Unit> Handle(UpdateCustomerCommand request, CancellationToken cancellationToken)
        {
            //do some stuff

            Mediator.Publish(new CustomersChanged());

            return Task.FromResult(new Unit());
        }
    }

When writing a unit test for this command, I obviously also must create an instance of MediatR (or a mockup) which I then pass to to the command during test execution.

        [Fact]
        public async void UpdateCustomerCommand_CustomerDataUpdatedOnDatabase()
        {
            //Arange

            var mediator = new Mediator(); // doesn't work that way..

            UpdateCustomerCommand command = new UpdateCustomerCommand();
            UpdateCustomerCommandHandler handler = new UpdateCustomerCommandHandler(mediator);

            //Act
            Unit x = await handler.Handle(command, new System.Threading.CancellationToken());

            //Asert
            //Do the assertion
        }

However, instanciating MediatR (outside of the MVC application, where I can utilize the existing dependency injection implementation) seems to be not that simple and frankly speaking I actually do not understand how I can do in my test method.

I understand that I potentially could use a dependency injection framework for which MediatR already provides an implementation (Ninject, etc.), but I actually do not want to use any other third party libraries in my unit tests apart from MediatR, just for the sake of creating an instance.

Is there a simpler way to instantiate MediatR which I might have overseen?

Answer

Alex picture Alex · Mar 31, 2019

You're on the right lines with or a mockup - you need to mock the IMediator

There's a few mocking libraries out there:

  • Moq
  • FakeItEasy
  • NSubstiutute

Moq is one of the most popular, so, using your test as an example:

    [Fact]
    public async void UpdateCustomerCommand_CustomerDataUpdatedOnDatabase()
    {
        //Arange
        var mediator = new  Mock<IMediator>();

        UpdateCustomerCommand command = new UpdateCustomerCommand();
        UpdateCustomerCommandHandler handler = new UpdateCustomerCommandHandler(mediator.Object);

        //Act
        Unit x = await handler.Handle(command, new System.Threading.CancellationToken());

        //Asert
        //Do the assertion

        //something like:
        mediator.Verify(x=>x.Publish(It.IsAny<CustomersChanged>()));
    }