给出以下界面:
public interface IFoo
{
bool Foo(string a, bool b = false);
}
尝试使用Moq模拟它:
var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);
在编译时出现以下错误:
表达式树可能不包含使用可选参数的调用或调用
我发现上面的问题在Moq的问题列表中被提升为enhancement,它似乎被分配到4.5版本(无论何时)。
我的问题是:鉴于以上情况不会很快得到解决,我该怎么办?我的选项是否只是在每次模拟它时显式设置可选参数的默认值(哪种类型在第一时间指定一个失败)或创建没有bool的重载(就像我会做的那样)在C#4之前?
或者有没有人遇到过更聪明的方法来解决这个问题?
答案 0 :(得分:72)
我相信您现在唯一的选择是在bool
的设置中明确包含Foo
参数。
我认为这不符合指定默认值的目的。默认值是调用代码的便利,但我认为您应该在测试中明确。假设您可以省略指定bool
参数。如果将来有人将b
的默认值更改为true
,会发生什么?这将导致测试失败(并且理所当然),但由于b
为false
的隐藏假设,它们将更难以修复。明确指定bool
参数还有另一个好处:它提高了测试的可读性。经过它们的人会很快知道有一个Foo
函数接受两个参数。那是我的2美分,至少是:)。
至于每次模拟它时都要指定它,不要复制代码:在函数中创建和/或初始化模拟,这样你只有一个变化点。如果你真的想要,你可以通过将Foo
的参数复制到这个初始化函数中来克服Moq明显的短缺:
public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
if(!b)
{
fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
}
else
{
...
}
}
答案 1 :(得分:6)
今天刚遇到这个问题,Moq不支持这个用例。 因此,对于这种情况,似乎重写该方法就足够了。
public interface IFoo
{
bool Foo(string a);
bool Foo(string a, bool b);
}
现在两种方法都可用,这个例子可行:
var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false);
答案 2 :(得分:0)
使用Moq版本4.10.1,我可以执行以下操作
带界面:
public interface IFoo
{
bool Foo(string a, bool b = false);
}
然后嘲笑
var mock = new Mock<IFoo>();
mock.Setup(mock => mock.Foo(It.IsAny<string>(), It.IsAny<bool>())).Returns(false);
使用第一个参数ok解析对Foo的调用
答案 3 :(得分:0)
就我而言,我的问题是我忘记为我的可选参数之一包含 It.IsAny<string>()
调用。一旦我对所有参数(包括可选参数)进行了 It.Is...
调用,它就会编译得很好。