134

给定以下界面:

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 问题列表中的一个增强功能,它似乎已分配给 4.5 版本(无论何时)。

我的问题是:鉴于上述情况不会很快得到解决,我该怎么办?我的选择是否只能在每次模拟时显式设置可选参数的默认值(这会破坏首先指定一个的点)或创建没有布尔的重载(就像我会做的那样在 C# 4) 之前?

或者有没有人遇到过更聪明的方法来克服这个问题?

4

4 回答 4

98

我相信您现在唯一的选择是boolFoo.

我不认为它违背了指定默认值的目的。默认值是为了方便调用代码,但我认为你应该在测试中明确。假设您可以省略指定bool参数。如果将来有人将默认值更改为bto会发生true什么?这将导致测试失败(这是理所当然的),但由于隐藏的假设bfalse. 显式指定bool参数还有另一个好处:它提高了测试的可读性。浏览过它们的人会很快知道有一个Foo函数接受两个参数。那是我的 2 美分,至少 :)

至于每次模拟时都指定它,不要重复代码:在函数中创建和/或初始化模拟,这样你就只有一个变化点。如果你真的想要,你可以通过将Foo's 参数复制到这个初始化函数中来克服 Moq 的明显缺点:

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false)
{
    if(!b)
    {
        fooMock.Setup(mock => mock.Foo(a, b)).Returns(false);
    }
    else
    {
        ...
    }
}
于 2012-10-19T16:41:35.527 回答
9

今天刚遇到这个问题,起订量不支持这个用例。因此,对于这种情况,似乎覆盖该方法就足够了。

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);
于 2016-03-28T13:57:30.100 回答
9

使用 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);

用第一个参数解决对 Foo 的调用 OK

于 2019-12-10T15:04:36.183 回答
0

就我而言,我的问题是我忘记包含It.IsAny<string>()对我的可选参数之一的调用。一旦我It.Is...调用了所有参数(包括可选参数),它就编译得很好。

于 2021-04-01T18:57:53.420 回答