MediatR 和 CQRS 测试。如何验证调用了该处理程序?

Posted

技术标签:

【中文标题】MediatR 和 CQRS 测试。如何验证调用了该处理程序?【英文标题】:MediatR and CQRS testing. How to verify that handler is called? 【发布时间】:2022-01-08 19:21:14 【问题描述】:

我目前正在尝试在我的项目中实施MediatR,并进行测试。我想介绍一下在发送请求时是否调用了处理程序的Handle

我有这个问题

public class GetUnitsQuery : IRequest<List<UnitResponse>>


处理程序:

public class GetUnitsHandler : IRequestHandler<GetUnitsQuery, List<UnitResponse>>

    readonly IUnitRepository UnitRepository;
    readonly IMapper Mapper;

    public GetUnitsHandler(IUnitRepository unitRepository, IMapper mapper)
    
        this.UnitRepository = unitRepository;
        Mapper = mapper;
    

    public async Task<List<UnitResponse>> Handle(GetUnitsQuery request, CancellationToken cancellationToken)
    
        return Mapper.Map<List<UnitResponse>>(UnitRepository.GetUnits());
    

从控制器发送请求:

var result = await Mediator.Send(query);

任何想法如何测试Handler 在使用MoQ 指定特定Query 时是否被调用?

【问题讨论】:

这样做有什么意义?这是 MediatR 的责任,不是你的。 我完全同意@Orhun,如果您使用的是 MediatR(产品),则不应对其进行测试...如果您正在实施自己的调解器,则应对其进行测试,但我对此表示怀疑从上下文来看是这样的......无论如何,我认为该产品带有一种机制,可以防止在没有处理程序的情况下注册查询......所以......为什么要担心? 【参考方案1】:

我没有使用 MoQ 来检查接收到的对特定处理程序的调用。但是,如果我使用 Nsubsitute 和 SpecFlow,我会在测试中执行类似的操作。

        var handler = ServiceLocator.Current.GetInstance<IRequestHandler<GetUnitsQuery, List<UnitResponse>>>();
        handler.Received().Handle(Arg.Any<GetUnitsQuery>(), Arg.Any<CancellationToken>());

【讨论】:

【参考方案2】:

就像其他人在 cmets 中所说的那样,您不需要测试 Mediator 的内部。

你的测试边界就是你的应用程序,所以假设一个控制器是这样的:

public class MyController : Controller 

    private readonly IMediator _mediator;

    public MyController(IMediator mediator)
    
        _mediator = mediator;
    

    public async IActionResult Index()
    
        var query = new GetUnitsQuery();

        var result = await Mediator.Send(query);

        return Ok(result);
    

我会验证 Mediator 是这样调用的:

public class MyControllerTests 

    [SetUp]
    public void SetUp()
    
        _mockMediator = new Mock<IMediator>();
        _myController = new MyController(_mockMediator.Object)
    

    [Test]
    public async void CallsMediator()
    
        // Arranged
        _mockMediator.SetUp(x=> x.Send(It.IsAny<GetUnitsQuery>()))
            .Returns (new List<UnitResponse>());

        // Act
        await _myController.Index();

        // Assert
        _mockMediator.Verify(x=> x.Send(It.IsAny<GetUnitsQuery>()), Times.Once);
    

【讨论】:

感谢您的回答,但我自己了解的就这么多了。我是否必须对其进行测试并不重要,我只是想就我所问的问题提供帮助:) 抱歉,您缺少单元测试的基础知识,只测试您的代码。

以上是关于MediatR 和 CQRS 测试。如何验证调用了该处理程序?的主要内容,如果未能解决你的问题,请参考以下文章

MediatR CQRS模式解决将消息发送与消息处理进行了解耦,他同时支持异步和同步来发送和监听消息.

.NET 5 源代码生成器——MediatR——CQRS

ABP CQRS 实现案例:基于 MediatR 实现

Mediatr:单元测试行为/验证

MediatR CQRS - 如何处理不存在的资源(asp.net core web api)

无法解析“MediatR.IMediator”类型的服务