如何在没有明确指定或使用重载的情况下在其签名中具有可选参数的方法?

时间:2012-10-18 14:53:10

标签: c# unit-testing moq

给出以下界面:

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之前?

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

4 个答案:

答案 0 :(得分:72)

我相信您现在唯一的选择是在bool的设置中明确包含Foo参数。

我认为这不符合指定默认值的目的。默认值是调用代码的便利,但我认为您应该在测试中明确。假设您可以省略指定bool参数。如果将来有人将b的默认值更改为true,会发生什么?这将导致测试失败(并且理所当然),但由于bfalse的隐藏假设,它们将更难以修复。明确指定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... 调用,它就会编译得很好。