Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to instantiate Mediatr as part of a Unit Test?

Tags:

cqrs

mediatr

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?

like image 284
Roland Avatar asked Mar 31 '19 16:03

Roland


People also ask

What is MediatR unit?

What is MediatR? MediatR is an implementation of the mediator pattern. It is a behavioural software design pattern that helps you to build simpler code by making all components communicate via a "mediator" object, instead of directly with each other.

What is MediatR .NET core?

MediatR Requests are very simple request-response style messages, where a single request is synchronously handled by a single handler (synchronous from the request point of view, not C# internal async/await). Good use cases here would be returning something from a database or updating a database.


2 Answers

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>()));
}
like image 122
Alex Avatar answered Sep 16 '22 12:09

Alex


To expand on the accepted answer, if you absolutely need to test interaction between two services using MediatR, you can always moq each publish/handler pair using callbacks:

_mediator = new Mock<IMediator>();
_mediator.Setup(m => m.Publish(It.IsAny<YourNotification>(), It.IsAny<CancellationToken>()))
   .Callback<YourNotification, CancellationToken>((notification, cToken) => 
      _yourHandlerService.Handle(notification, cToken));

The above code, basically says if _mediator gets YourNotification via Publish method, then it will forward it to _yourHandlerService via Handle method. You can repeat that Setup for each type of mediator INotification you want to handle.

like image 36
Eternal21 Avatar answered Sep 16 '22 12:09

Eternal21