如何在单元测试中实例化Mediatr?

Rol*_*and 3 cqrs mediatr

我正在尝试为基于CQRS / ES模式的MVC Core 2.2应用程序构建xUnit Test项目。我将MediatR用作MVC应用程序中CQRS / ES模式的一部分。

在我要测试的命令之一中,一旦客户记录已更新,我就注入MediatR来发布事件。有点像这样:

    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());
        }
    }
Run Code Online (Sandbox Code Playgroud)

对此命令编写单元测试时,显然,我还必须创建MediatR(或模型)实例,然后在测试执行期间将其传递给命令。

        [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
        }
Run Code Online (Sandbox Code Playgroud)

但是,实例化MediatR(在MVC应用程序之外,我可以在其中使用现有的依赖注入实现)似乎并不那么简单,坦白地说,我实际上不了解如何在测试方法中进行操作。

我知道我可能会使用MediatR已经为其提供实现的依赖注入框架(Ninject等),但是我实际上不想在我的单元测试中使用除MediatR之外的任何其他第三方库,只是为了创建实例。

有没有一种更简单的实例化MediatR的方法,我可能已经对此进行了监督?

Ete*_*l21 9

为了扩展已接受的答案,如果您绝对需要使用 MediatR 测试两个服务之间的交互,您始终可以使用回调来最小化每个发布/处理程序对:

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

上面的代码基本上是说如果 _mediator 获取YourNotificationviaPublish方法,那么它会将其转发给_yourHandlerServiceviaHandle方法。您可以对要处理的Setup每种类型的中介者重复此操作。INotification


Ale*_*lex 7

你在右边线用or a mockup-你需要嘲笑IMediator

这里有一些模拟库:

  • 起订量
  • FakeItEasy
  • N替代品

最小起订量是最受欢迎的一种,因此,以您的测试为例:

    [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>()));
    }
Run Code Online (Sandbox Code Playgroud)

  • @Alex 单独测试作为第一步,但至少有一些集成测试很好,非常好。我们在一个项目中遇到过这个问题,在这个项目中,单元测试很好地涵盖了所有内容,但几乎所有的集成测试都在某个时候导致了非常大的问题。很多单元测试,但肯定有一些集成。 (6认同)
  • @Roland,那么您就不再是“单元测试”,而是集成测试。您需要创建一个“真实的”介体,连接所有依赖项等。避免这种情况。隔离测试零件。 (3认同)
  • 好吧,我理解这个概念(同时我也很惊讶)。但是,如果我实际上想检查任何通知的接收者的状态(比方说,要检查我想根据 CustomersChanged 事件检查某些缓存是否已删除),该怎么办?这基本上迫使我制作 MediatR 的真实实例 =&gt; 有没有简单的方法可以做到这一点? (2认同)
  • 你是对的。我在这件事上走错了路!感谢您的回答; 帮了我很多! (2认同)
  • 如果目的是“测试命令”,那么此解决方案不只是测试命令是否被调用。它测试命令处理程序是否调用 Publish 方法。这只是样板代码。需要测试的真正重要的代码是特定 MediatR 命令或查询内的代码。这就是真正的工作完成的地方,也是一个命令或查询与另一个命令或查询不同的地方。 (2认同)