问题
I am able to stub a static extension method using Rhino Mocks but if I cast the return value to another type, I get an error. Why?
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);
}
}
Here is the error:
System.InvalidOperationException : Type 'System.Decimal' doesn't match the return type 'System.Double' for method 'INumberGenerator.GetDouble();'
回答1:
Warning: this is really a suspicion more than anything else
The problem is that you're not really stubbing the extension methods at all - you're stubbing GetDouble
in both cases.
I haven't looked at the code for Rhino Mocks for a while, but I suspect that the Stub
method is basically saying:
- Get ready for some calls on the mock!
- Call the delegate passed in as an argument
- Note which calls were made
That means you're effectively doing this:
canGetDecimal.Stub(ng => ng.GetDouble()).Return(1.2d);
canGetDecimal.Stub(ng => (decimal) ng.GetDouble()).Return(1.2m);
At that point, it would notice that you called GetDouble
- but then you're trying to set the return value to 1.2m, which is invalid.
You could validate this pretty easily, with some logging. Add a log line to GetTheDoubleCastToDecimal
and then split out the Stub
call from the Return
call:
Console.WriteLine("Before Stub");
var stubCall = canGetDecimal.Stub(obj => obj.GetTheDoubleCastToDecimal();
Console.WriteLine("After Stub");
stubCall.Return(1.2m);
I strongly suspect you'll find that whatever logging you add into the extension method is still logged between "Before Stub" and "After Stub" - showing that the extension method isn't being mocked out.
Moral: don't try to mock/stub extension methods. They're not polymorphic; they're just static methods, and it would be pretty tricky to fake them without deep wizardry. Only try to fake out genuinely polymorphic operations.
回答2:
There is possibility to stub extension method or any other static method without any framework. This requires a bit of additional afford.
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);
}
}
It allows you to substitute the implementation. You can just change value of _doSumm
field.
来源:https://stackoverflow.com/questions/17661979/stubbing-a-static-extension-method-seems-to-work-in-rhino-mocks-unless-i-cast-th