4

我可以使用 Rhino Mocks 存根静态扩展方法,但是如果我将返回值转换为另一种类型,则会出现错误。为什么?

using Rhino.Mocks;

public interface INumberGenerator
{
    double GetDouble();
}

static class NumberGeneratorExtensionMethods
{
    public static double GetTheDouble(this INumberGenerator input)
    {
        return input.GetDouble();
    }

    public static decimal GetTheDoubleCastToDecimal(this INumberGenerator input)
    {
        return (decimal) input.GetDouble();
    }
}

class MockExample
{
    public void TriggerTheError()
    {
        var stub = MockRepository.GenerateStub<INumberGenerator>();

        // This works
        stub.Stub(obj => obj.GetTheDouble()).Return(1.2d);

        // This throws the error
        stub.Stub(obj => obj.GetTheDoubleCastToDecimal()).Return(1.2m);
    }
}

这是错误:

System.InvalidOperationException:类型“System.Decimal”与方法“INumberGenerator.GetDouble();”的返回类型“System.Double”不匹配

4

2 回答 2

10

警告:这确实比其他任何事情都更令人怀疑

问题是您根本没有真正存根扩展方法 -GetDouble在这两种情况下您都在存根。

有段时间没看Rhino Mocks的代码了,但我怀疑Stub方法基本上是在说:

  • 准备好模拟一些电话!
  • 调用作为参数传入的委托
  • 注意拨打了哪些电话

这意味着您正在有效地执行此操作:

canGetDecimal.Stub(ng => ng.GetDouble()).Return(1.2d);
canGetDecimal.Stub(ng => (decimal) ng.GetDouble()).Return(1.2m);

此时,它会注意到您调用了GetDouble- 但随后您尝试将返回值设置为 1.2m,这是无效的。

您可以通过一些日志记录很容易地验证这一点。添加一个日志行GetTheDoubleCastToDecimal,然后将Stub呼叫从Return呼叫中分离出来:

Console.WriteLine("Before Stub");
var stubCall = canGetDecimal.Stub(obj => obj.GetTheDoubleCastToDecimal();
Console.WriteLine("After Stub");
stubCall.Return(1.2m);

我强烈怀疑您会发现添加到扩展方法中的任何日志记录仍然记录在“存根之前”和“存根之后”之间 - 表明扩展方法没有被模拟出来。

道德:不要尝试模拟/存根扩展方法。它们不是多态的;它们只是静态方法,如果没有深奥的魔法,要伪造它们是非常棘手的。只尝试伪造真正的多态操作。

于 2013-07-15T19:15:20.987 回答
1

有可能在没有任何框架的情况下存根扩展方法或任何其他静态方法。这需要一些额外的负担。

public static class MyExtensions
{
    public static Func<int,int, int> _doSumm = (x, y) => x + y;

    public static int Summ(this int x, int y)
    {
        return _doSumm(x, y);
    }
}

它允许您替换实现。您可以更改_doSumm字段的值。

于 2015-01-30T08:28:56.513 回答