Warm tip: This article is reproduced from stackoverflow.com, please click
.net-core c# xunit moq

Generic method for verifying whether a mocked method called

发布于 2020-04-03 23:19:44

I am building generic test helper method to verify whether a method is called in the mock with the given type. In my example I am mocking IMediator from the library MediatR. For mocking I am using Moq library

Let's see the code. For the sake of simplicity I made a "dummy" service and a corresponding test, to only focus on the problem. My production code:

public class Service
{
    private readonly IMediator _mediator;

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

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

And the corresponding test:

    [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);
    }

My assert method does fail, unexpectedly, with the following reason:

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):

On the other hand, If I specify the type directly in the verification method, the test passes. The passing assert method looks as the following:

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

It looks quite strange to me, since the second assert method works flawlesly. But if I use the generic type parameter and pas it on to the verify method, it fails. What am I doing wrong? Am I not aware of some important underlying behaviour of C#/.NET.Core? Thanks for the help!

Questioner
mirind4
Viewed
41
Johnny 2020-01-31 21:30

It seems that the problem is with your constraint where TRequest : class.

If you look at the IMediator you will find two methods:

  1. Receive IRequest<TResponse>

  2. Receive object

It is confusing to moq to really figure out which override to use. Try being really explicit with the types to really point to the right method, for example:

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

or

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);
}