How do I Moq a method that has an optional argument in its signature without explicitly specifying it or using an overload?

扶醉桌前 提交于 2019-11-26 11:08:03

问题


Given the following interface:

public interface IFoo
{
    bool Foo(string a, bool b = false);
}

Attempting to mock it using Moq:

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);

gives the following error at compile time:

An expression tree may not contain a call or invocation that uses optional arguments

I\'ve found the issue above raised as an enhancement in Moq\'s list of issues and it appears to be assigned to the 4.5 release (whenever that is).

My question is: what should I do given that the above is not going to be fixed anytime soon? Are my options only to either explicitly set the default value of the optional parameter every time I mock it (which kind of defeats the point of specifying one in the first place) or to create an overload without the bool (like what I would have done prior to C# 4)?

Or has anyone come across a more clever way to overcome this issue?


回答1:


I believe your only choice right now is to explicitly include the bool parameter in the setup for Foo.

I don't think it defeats the purpose of specifying a default value. The default value is a convenience for calling code, but I think that you should be explicit in your tests. Say you could leave out specifying the bool parameter. What happens if, in future, someone changes the default value of b to true? This will lead to failing tests (and rightfully so), but they will be more difficult to fix because of the hidden assumption that b is false. Explicitly specifying the bool parameter has another benefit: it improves the readability of your tests. Someone going through them will quickly know that there's one Foo function that accepts two parameters. That's my 2 cents, at least :)

As for specifying it every time you mock it, don't duplicate code: create and/or initialise the mock in a function, so that you only have a single point of change. If you really want to, you can overcome Moq's apparent short-coming here by duplicating Foo's parameters into this initialisation function:

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
    if(!b)
    {
        fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
    }
    else
    {
        ...
    }
}



回答2:


Just encountered this issue today, Moq doesn't support this use case. So, seems that overriding the method would be sufficient for this case.

public interface IFoo
{
    bool Foo(string a);

    bool Foo(string a, bool b);
}

Now both methods are available and this example would work:

var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);


来源:https://stackoverflow.com/questions/12957537/how-do-i-moq-a-method-that-has-an-optional-argument-in-its-signature-without-exp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!