除非我转换返回变量,否则在Rhino Mocks中使用stubbing静态扩展方法似乎有效.为什么?

mat*_*ndr 4 c# rhino-mocks

我能够使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是错误:

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

Jon*_*eet 10

警告:这真的是一种怀疑,而不是其他任何事情

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

我暂时没有查看Rhino Mocks的代码,但我怀疑Stub方法基本上是这样说的:

  • 准备一些关于模拟的电话!
  • 调用传入的委托作为参数
  • 请注意进行了哪些调用

这意味着你有效地做到了这一点:

canGetDecimal.Stub(ng => ng.GetDouble()).Return(1.2d);
canGetDecimal.Stub(ng => (decimal) ng.GetDouble()).Return(1.2m);
Run Code Online (Sandbox Code Playgroud)

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

您可以通过一些日志记录轻松验证这一点.添加日志行GetTheDoubleCastToDecimal,然后StubReturn呼叫中分出呼叫:

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

我强烈怀疑你会发现你添加到扩展方法中的任何日志记录仍然记录在"Before Stub"和"After Stub"之间 - 显示扩展方法没有被模拟掉.

道德:不要试图模拟/存根扩展方法.它们不是多态的; 它们只是静态方法,在没有深刻魔法的情况下伪造它们会非常棘手.只是试图伪造真正的多态操作.