Moq + 单元测试 - System.Reflection.TargetParameterCountException: 参数计数不匹配

78

我试图在多参数函数中使用lambda表达式,但是当我尝试调用mock.Object.Convert(value, null, null, null);这一行时,Moq会在运行时抛出以下异常:

System.Reflection.TargetParameterCountException: 参数计数不匹配

代码如下:

var mock = new Mock<IValueConverter>();

mock.Setup(conv => conv.Convert(It.IsAny<Object>(), It.IsAny<Type>(),
    It.IsAny<Object>(), It.IsAny<CultureInfo>())).Returns((Int32 num) => num + 5);

var value = 5;
var expected = 10;
var actual = mock.Object.Convert(value, null, null, null);

应该如何正确实现它?

4个回答

141

这是您的Returns子句。您正在设置一个有4个参数的方法,但只使用了1个参数的lambda表达式。我运行了以下代码而没有问题:

[TestMethod]
public void IValueConverter()
{
    var myStub = new Mock<IValueConverter>();
    myStub.Setup(conv => conv.Convert(It.IsAny<object>(), It.IsAny<Type>(), It.IsAny<object>(), It.IsAny<CultureInfo>())).
        Returns((object one, Type two, object three, CultureInfo four) => (int)one + 5);

    var value = 5;
    var expected = 10;

    var actual = myStub.Object.Convert(value, null, null, null);

    Assert.AreEqual<int>(expected, (int) actual);
}

没有异常,测试通过。


我本来想询问这是否是对框架的测试,但我认为我应该给予怀疑的好处,也许这是临时代码,尝试使模拟行为正常。 - Erik Dietrich
我认为也是,但它仍然让我发笑。 - Ritch Melton
我听到你的声音了。当我执行代码时,我想:“是的,框架库仍然正常工作。” :) - Erik Dietrich

8

虽然不是针对问题的答案,但也许对未来的谷歌搜索者有用:

我有一个回调函数,它与设置方法的签名不匹配。

Mock
    .Setup(r => r.GetNextCustomerNumber(It.IsAny<int>()))
    .Returns(AccountCounter++)
    .Callback<string, int>(badStringParam, leadingDigit =>
    {
        // Doing stuff here, note that the 'GetNextCustomerNumber' signature is a single int 
        // but the callback unreasonably expects an additional string parameter.
    });

这是一些重构的结果,而重构工具当然无法意识到Callback签名不正确


哇,我一直在为这个问题苦恼,一直忽略了回调函数,直到我看了你的帖子。非常有帮助,我很高兴你发布了它。 - dblood
这也是我的问题。我向一个方法添加了一个参数,修复了Setup()调用,但是错过了Callback()参数。 - Pete

1
也许是因为您传递了“null”,但 “It.IsAny<Object>()” 需要除“null”以外的任何对象?如果按照以下方式操作,会发生什么情况?
var actual = mock.Object.Convert(value, new object(), typeof(object), CultureInfo.CurrentCulture);

这只是我猜测的结果,我更熟悉Rhino.Mocks。


我的第二个猜测:

查看下载附带的Moq.chm后,

您正在使用Setup(Expression<Action<T>>)方法,该方法“为调用void方法设置模拟类型上的设置”。

您需要使用Setup<TResult>(Expression<Func<T,TResult>>)方法,该方法“为调用返回值方法设置模拟类型上的设置”。

因此,您可以尝试:

mock.Setup<Int32>(
    conv => {
        conv.Convert(
            It.IsAny<Object>(), 
            It.IsAny<Type>(),
            It.IsAny<Object>(), 
            It.IsAny<CultureInfo>());
        return  num + 5;
        });

mock.Setup<TResult> 推断返回类型为 Object,因为 Convert 方法返回一个 Object。 - myermian

1
在我的情况下,我认为Returns<>中的类型是输出类型,但实际上它是输入类型。因此,如果你有一个方法:
public virtual string Foo(int a, int b) { ... }

正确的语句是.Returns<int, int>(...),而不是我最初想到的.Returns<string>(...)
我的错误是因为最初使用相同的输入和返回类型测试函数 - 例如public virtual string Foo(string a)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接