【问题标题】:xUnit throws System.MissingMethodException when calling handler (MediatR)xunit抛出system.missingmethodexception在调用处理程序时(MediaTr)
【发布时间】:2021-01-09 00:38:56
【问题描述】:

我有一个 .NET Core v2.1。带有 CQRS 的 API。为了简化控制器,我正在使用 MediatR。 现在我正在尝试使用 xUnit 为我的处理程序编写一些单元测试,但它抛出了这个异常:

StackTrace 执行结果:在 Research.Application.EventoContext.Commands.ConfirmarPresencaCommandHandler.Handle(ConfirmarPresensaCommand 请求,CancellationToken 取消令牌)在 System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& 状态机)在 Research.Application.EventoContext.Commands.ConfirmarPresencaCommandHandler.Handle(ConfirmarPresensaCommand 请求,CancellationToken 取消令牌)在 Research.Application.EventoContext.Commands.ConfirmarPresencaCommandHandler.Handle() 在 C:\Users\public\Desktop\Research\ResearchAPI\app\src\Research.Teste\Commands\EventoCommands.cs:line 38 --- 从以前抛出异常的位置结束堆栈跟踪 --- Mensagem do Resultado: System.MissingMethodException : 找不到方法:'System.Threading.Tasks.Task1<!!0> MediatR.IMediator.Send(MediatR.IRequest1, System.Threading.CancellationToken)'。

这是我的命令和处理程序。由于我没有存储库,因此我使用 DbSets 和 SaveChangeAsync() 方法创建了一个数据上下文接口:

public class ConfirmarPresensaCommand : IRequest<PontuacaoVM>
{
    public Guid id_usuario { get; set; }
    public Guid id_evento { get; set; }
    public List<Guid> sub_eventos { get; set; }
}

public class ConfirmarPresensaCommandHandler : IRequestHandler<ConfirmarPresensaCommand, PontuacaoVM>
{
    private readonly IMySqlContext _context;
    private readonly IMediator _mediator;

    public ConfirmarPresensaCommandHandler(IMySqlContext context, IMediator mediator)
    {
        _context = context;
        _mediator = mediator;
    }

    public async Task<PontuacaoVM> Handle(ConfirmarPresensaCommand request, CancellationToken cancellationToken)
    {
        var _presenca = await _context.PresencasUsuarios
                                      .Include(p => p.SubEvento)
                                      .Where(p => p.CodigoUsuario == request.id_usuario &&
                                                  p.SubEvento.CodigoEvento == request.id_evento)
                                      .FirstOrDefaultAsync();

        if (_presenca == null)
        {
            var _subEvento = await _context.SubEventos
                                           .Where(s => s.CodigoEvento == request.id_evento &&
                                                       s.Principal)
                                           .FirstOrDefaultAsync();

            await _context.PresencasUsuarios.AddAsync(new PresencaUsuario
            {
                CodigoUsuario = request.id_usuario,
                CodigoSubEvento = _subEvento.Codigo,
            }, cancellationToken);

            await _context.SaveChangesAsync(cancellationToken);
        }

        return await _mediator.Send(new GerarPontuacaoCommand(request.id_usuario, "Evento", "Confirmar"));
    }
}

这是我的测试。我正在使用 Moq.EntityFrameworkCore v2.0.1:

public class ConfirmarEventoTeste : TesteUtils
{
    public Mock<IMySqlContext> _moqContext;
    public Mock<IMediator> _moqMediator;
    
    public ConfirmarEventoTeste()
    {
        _moqContext = new Mock<IMySqlContext>();
        _moqMediator = new Mock<IMediator>();

        _moqMediator.Setup(m => m.Send(It.IsAny<ConfirmarPresencaCommand>(), It.IsAny<CancellationToken>()).ReturnsAsync(It.IsAny<PontuacaoVM>());
    }

    [Fact]
    public async Task ConfirmarPresenca_Sucesso()
    {
        var _command = new ConfirmarPresensaCommand();
        var _handler = new ConfirmarPresensaCommandHandler(_moqContext.Object, _moqMediator.Object);

        var _result = await _handler.Handle(_command, new CancellationToken());

        Assert.NotNull(_result);
    }
}

我知道我需要为单元测试工作编写设置,但现在我担心的是测试中的 Handle() 调用甚至没有命中我的 Handler。

有人可以帮我吗?

【问题讨论】:

    标签: asp.net-core moq xunit cqrs mediatr


    【解决方案1】:

    要解决这个问题,你需要mock Send mehod in MediatR

    _mediatorMock = new Mock<IMediator>();
    _mediatorMock.Setup(x => x.Send(It.IsAny<GerarPontuacaoCommand>(), It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
    

    另外,这可能对你有帮助 Mocking MediatR 3 with Moq

    但我更喜欢另一种测试MediatR 的方法。我会更喜欢integration tests。因为使用integration tests,您可以检查此包的正确行为。此外,这种方法使用开发人员来测试github 官方示例中的行为。

    他们执行以下步骤(常用算法)

    1. 创建Dependency injection容器的实例
    2. 注册您的处理程序
    3. 获取IMediator的实例
    4. 使用Send方法发送请求
    5. 最后查看回复Message

    来自微软的依赖注入

    如果您使用来自Microsoft.Extensions.DependencyInjectionpackage 的通用DI,请执行以下步骤:

    1. 创建 DI 容器实例
    var services = new ServiceCollection();
    
    1. 使用package注册处理程序
    services.AddMediatR(typeof(CustomerLoginRequest).Assembly);
    
    1. 在添加所有依赖项后的最后一刻构建service provider
    var serviceProvider = services.BuildServiceProvider();
    
    1. 从 DI 获得调解员服务
    var mediator = serviceProvider.GetRequiredService<IMediator>();
    
    1. 将您的mediator 放入您的处理程序类并执行它。
    2. 另外,Assert 结果。

    来自其他包的依赖注入

    如果您为 DI 使用另一个包 - 您可以检查 github 存储库中的示例并通过示例创建自己的测试。他们将StructureMap 用于DI。

    【讨论】:

    • 我已经尝试了这两种方法,仍然没有运气。当我消除内部调解器并直接调用处理程序时,它工作得很好。但仍然无法测试控制器,例如,由于 MediatR。
    • 您是否创建了 DI 容器并在您的 Controllers 中注入了 MediatR
    猜你喜欢
    • 2019-08-25
    • 2018-08-09
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 2020-12-08
    • 2019-07-02
    • 1970-01-01
    • 2020-03-14
    相关资源
    最近更新 更多