Weird error using Rhino Mocks “type doesn't ma

2019-08-11 12:37发布

问题:

EDIT: I played with this example and now my question is a different one entirely.

When I run this example:

using Rhino.Mocks;

public interface IInterface
{
    decimal GetDecimal();
}

static class Util
{
    public static double? DecToDouble(this IInterface input)
    {
        return (double) input.GetDecimal();
    }
}

class MockExample
{
    public void RunThis()
    {
        var stubReader = MockRepository.GenerateStub<IInterface>();
        stubReader.Stub(sr => sr.DecToDouble()).Return(1.2);
    }
}

I get this error:

System.InvalidOperationException : Type 'System.Double' doesn't match the return type 'System.Decimal' for method 'IInterface.GetDecimal();'

Why?

回答1:

Rhino Mocks can only intercept calls that are made through the stubbed interface. The extension method above is compiled to something like:

Util.DecToDouble(sr)

This means that your setup/return basically reads like this:

stubReader.Stub(sr => Util.DecToDouble(sr)).Return(1.2);

That clearly is not going to work (with most mocking frameworks). The proper way to achieve what you want is:

stubReader.Stub(sr => sr.GetDecimal())).Return(1.2);

After further investigation: Rhino Mocks internally connects the method declared by Stub() to the value declared by Return() by invoking the delegate passed to Stub() and saving the last applied method invocation. This saved method invocation is afterwards connected to the return value. When doing this Rhino Mocks internally checks whether the return type of the saved invocation matches the type of the value. If they don't match Rhino Mocks raises the exception you are seeing. The correct way to define the stubbing would be

    decimal val = 1.2M;
    stubReader.Stub(sr => sr.DecToDouble()).Return(val);

But this does not compile, because the generic type params of Stub() and Return() must be compatible. So really the only way to define the stubbing is to ignore the extension methods and only stub the methods defined in the interface.



回答2:

If you're trying to mock IInterface then you're stubbing the wrong method:

public void RunThis()
{
    var stubReader = MockRepository.GenerateStub<IInterface>();
    stubReader.Stub(sr => sr.GetDecimal()).Return(1.2);
}

If you're trying to stub DecToDouble, you can't with RhinoMocks. Extension methods are compiled to static method calls which can't be mocked by RhinoMocks because they're bound at compile-time. Some stub frameworks use low-level profiler calls to intercept static calls but RhinoMocks does not have that capability that I know of.

See this question for a similar discussion.