This is related to a MediatR 3.0 upgrade, but I'm sure the problem extends to any method that is mock-able that uses a default value as one of its parameters.
Here is the interface I'm trying to mock:
public interface IMediator
{
Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = null);
Task Send(IRequest request, CancellationToken cancellationToken = null);
Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = null) where TNotification : INotification;
}
We have thousands of unit tests that mocked the older version of this interface (w/out the CancellationToken). An example of that code:
mockMediator.Verify(mock => mock.Send(It.Is<CampaignDetailQuery>(c => c.CampaignId == campaignId)));
after upgrading the library to the interface above, for each unit test I'm getting this error:
An expression tree may not contain a call or invocation that uses optional arguments
We'd have to change thousands of unit tests to explicitly pass the default parameter to the expression tree like this:
mockMediator.Verify(mock => mock.Send(It.Is<IndexQuery>(q => q.OrganizationId == null), default(CancellationToken)));
which is a lot of changes.
Any plans for Moq to support NOT having to explicitly pass in default parameters in expression trees to mockable members?
The error seems to be a compilation error, so, Moq can't change the
compiler, no
On Fri, Jan 6, 2017, 8:35 AM Michael McCarthy notifications@github.com
wrote:
This is related to a MediatR 3.0 upgrade, but I'm sure the problem extends
to any method that is mock-able that uses a default value as one of its
parameters.Here is the interface I'm trying to mock:
public interface IMediator
{
TaskSend (IRequest request, CancellationToken cancellationToken = null); Task Send(IRequest request, CancellationToken cancellationToken = null); Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = null) where TNotification : INotification;}
We have thousands of unit tests that mocked the older version of this
interface (w/out the CancellationToken). An example of that code:mockMediator.Verify(mock => mock.Send(It.Is
(c => c.CampaignId == campaignId))); after upgrading the library to the interface above, for each unit test I'm
getting this error:An expression tree may not contain a call or invocation that uses optional arguments
We'd have to change thousands of unit tests to explicitly pass the default
parameter to the expression tree like this:mockMediator.Verify(mock => mock.Send(It.Is
(q => q.OrganizationId == null), default(CancellationToken))); which is a lot of changes.
Any plans for Moq to support NOT having to explicitly pass in default
parameters in expression trees to mockable members?—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/moq/moq4/issues/316, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKW625YhHcHxIRtBG5_Pc2vAYuHvzSDks5rPkMvgaJpZM4Lct9q
.>
--
/kzu from mobile
As long as Moq is based on expression trees, and that compiler restriction isn't relaxed, there's just no way to solve this.
Here's a suggestion for a workaround that may or may not work in your situation.
Put the CancellationToken-less methods back in the interface. (This will solve the immediate issue encountered in your Moq-based tests.) For example:
partial class IMediator
{
Task Send(IRequest request);
Task Send(IRequest request, CancellationToken cancellationToken);
}
Then declare a base type MediatorBase from which your implementations will inherit (instead of implementing IMediator directly):
abstract partial class MediatorBase : IMediator
{
public Task Send(IRequest request) => Send(request, CancellationToken.None);
public abstract Task Send(IRequest request, CancellationToken cancellationToken);
}
Or, if you prefer explicit interface implementation:
abstract partial class MediatorBase : IMediator
{
Task IMediator.Send(IRequest request) => Send(request, CancellationToken.None);
Task IMediator.Send(IRequest request, CancellationToken cancellationToken) => Send(request, cancellationToken);
protected abstract Task Send(IRequest request, CancellationToken cancellationToken);
}
(P.S.: Starting with C# 8 / .NET Core 3, you may be able to skip the base class and instead define the CancellationToken-less method as a default interface method.)
I got this working by doing the following:
mediatorMock.Setup(x => x.Send(It.IsAny<SomeCommand>(), It.IsAny<CancellationToken>())) .ReturnsAsync(new SomeResult());
and then
mediatorMock.Verify(x => x.Send(It.IsAny<SomeCommand>(), It.IsAny<CancellationToken>()));
Thanks DaanDL, this worked for me.
Most helpful comment
I got this working by doing the following:
mediatorMock.Setup(x => x.Send(It.IsAny<SomeCommand>(), It.IsAny<CancellationToken>())) .ReturnsAsync(new SomeResult());and then
mediatorMock.Verify(x => x.Send(It.IsAny<SomeCommand>(), It.IsAny<CancellationToken>()));