mirind4
mirind4

Reputation: 1573

Generic method for verifying whether a mocked method called

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!

Upvotes: 2

Views: 614

Answers (1)

Johnny
Johnny

Reputation: 9509

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

Upvotes: 1

Related Questions