验证模拟方法是否调用的通用方法

Generic method for verifying whether a mocked method called

我正在构建通用测试辅助方法来验证是否在具有给定类型的模拟中调用了一个方法。在我的示例中,我从库 MediatR. For mocking I am using Moq library

中模拟 IMediator

让我们看看代码。为了简单起见,我做了一个 "dummy" 服务和相应的测试,只关注问题。 我的生产代码:

public class Service
{
    private readonly IMediator _mediator;

    public Service(IMediator mediator)
    {
        _mediator = mediator;
    }

    public void SendQuery()
    {
        _mediator.Send(new GetAllProductsQuery());
    }
}

以及对应的测试:

    [Fact]
    public void  WhenSendQueryCalled_ThenGetAllProductsQuerySend()
    {
        //Arrange
        var mockedMediator = new Mock<IMediator>();
        var service = new Service(mockedMediator.Object);

        //Act
        service.SendQuery();

        //Assert
        CheckThatRequestSentViaMediator<GetAllProductsQuery>(mockedMediator);
    }

    private void CheckThatRequestSentViaMediator<TRequest>(Mock<IMediator> mockedMediator) where TRequest : class
    {
        mockedMediator.Verify(mock => mock.Send(It.IsAny<TRequest>(), It.IsAny<CancellationToken>()), Times.Once);
    }

我的 assert 方法确实失败了,原因如下:

Moq.MockException: 
Expected invocation on the mock once, but was 0 times: mock => mock.Send(It.IsAny<GetAllProductsQuery>(), It.IsAny<CancellationToken>())

Performed invocations:

   Mock<IMediator:1> (mock):

另一方面,如果我在验证方法中直接指定类型,则测试通过。传递的断言方法如下所示:

    private void CheckGetAllProductsQuerySentViaMediator(Mock<IMediator> mockedMediator)
    {
        mockedMediator.Verify(mock => mock.Send(It.IsAny<GetAllProductsQuery>(), It.IsAny<CancellationToken>()), Times.Once);
    }

我觉得很奇怪,因为第二个 assert 方法工作得很好。但是,如果我使用泛型类型参数并将其传递给验证方法,它就会失败。我究竟做错了什么?我不知道 C#/.NET.Core 的一些重要的潜在行为吗?感谢您的帮助!

看来问题出在你的约束 where TRequest : class 上。

如果您查看 IMediator,您会发现两种方法:

  1. Receive IRequest<TResponse>

  2. Receive object

moq 很难真正弄清楚要使用哪个覆盖。尝试对类型真正明确以真正指向正确的方法,例如:

private static void CheckThatRequestSentViaMediator<T>(Mock<IMediator> mediator) 
    where T : IRequest<T>

private static void CheckThatRequestSentViaMediator<T>(Mock<IMediator> mediator) where T : class
{
    mediator.Verify(mock => mock.Send(It.IsAny<IRequest<T>>(), It.IsAny<CancellationToken>()), Times.Once);
}