How to use the Moq method, which has an optional argument in its signature without explicitly specifying it or using overload?

Given the following interface:

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

Trying to mock him with Moq:

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

gives the following error at compile time:

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

I found the problem above, raised as an improvement in the Moq error list, and it seems to have been assigned to version 4.5 (whenever possible).

My question is: what should I do, given that the foregoing will not be fixed in the near future? Are my options just to either explicitly set a default value for an optional parameter every time I scoff at it (what kind of point the point wins first), or to create an overload without a bool (for example, what would I do to C # 4)?

Or can someone find a smarter way to overcome this problem?

+80
c # unit-testing moq
Oct. 18 '12 at 14:53
source share
2 answers

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

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

As for pointing it out every time you scoff at it, do not duplicate the code: create and / or initialize the layout in the function so that you have only one change point. If you really want to, you can overcome the apparent Moq short circuit by duplicating the Foo parameters in this initialization function:

 public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false) { if(!b) { fooMock.Setup(mock => mock.Foo(a, b)).Returns(false); } else { ... } } 
+62
Oct 19 '12 at 16:41
source share

Just ran into this problem today, Moq does not support this use case. So, it seems that overriding the method will suffice for this case.

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

Both methods are now available, and this example will work:

 var mock = new Mock<IFoo>(); mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false); 
+5
Mar 28 '16 at 13:57
source share



All Articles