I have problems with stubbing a method with a ref
parameter.
I want to stub that method for a certain input value and check that it was called.
My attempt:
// Variables needed - can be skipped
var activity = MockRepository.GenerateMock<ICompositeActivity<object>>();
var context = new Context<object>(new object());
var inputValue = MockRepository.GenerateMock<IActivity<object>>();
var outputValue = MockRepository.GenerateMock<IActivity<object>>();
var executeCalled = 0;
// The stub:
activity.Stub(
x =>
x.Execute(Arg<Context<object>>.Is.Same(context),
ref Arg<IActivity<object>>.Ref(Is.Same(inputValue), outputValue).Dummy))
.WhenCalled(i => ++executeCalled).Return(true);
var tmp = inputValue;
tmp.ShouldBeTheSameAs(inputValue);
// The execution:
activity.Execute(context, ref tmp);
// The check:
inputValue.ShouldNotBeTheSameAs(outputValue); // Passes, ok
tmp.ShouldBeTheSameAs(outputValue); // Passes, ok
executeCalled.ShouldEqual(1); // Passes, ok
// Passes. Why?
activity.AssertWasCalled(
x =>
x.Execute(Arg<Context<object>>.Is.Same(context),
ref Arg<IActivity<object>>.Ref(Is.Same(outputValue), null).Dummy));
// Doesn't pass. Why?
activity.AssertWasCalled(
x =>
x.Execute(Arg<Context<object>>.Is.Same(context),
ref Arg<IActivity<object>>.Ref(Is.Same(inputValue), outputValue).Dummy));
BTW: I know, that this test doesn't make any sense, because it doesn't test any real classes. It's a condensed version of my real test to illustrate the problem.
As you can see, there is something strange going on:
The stub of the execute method is correct and it is called, because executeCalled
is 1 and the tmp
parameter has been changed from inputValue
to outputValue
.
BUT:
- The first check with
AssertWasCalled
passes, although it checks, whetherExecute
was called with outputValue, which it wasn't. - The second check with
AssertWasCalled
failes, although it checks, whetherExecute
was called with inputValue, which it was.
Furthermore, when I check i.Arguments[1]
inside WhenCalled
of the stub, it is outputValue
, not inputValue
... It looks like Rhino Mocks is changing the input value to the specified return value, before even calling the stub...
Is this a bug in Rhino Mocks? Or am I missing something? If it is a bug, are there any workarounds, beside the executeCalled
counter?
The same test, a bit cleaned up:
It passes. It clearly shows that Rhino records the output value, not the original input value. It is rarely recognized, because you need this temp variable to test this effect.
The following test also passes:
It can be seen as a bug, but is quite a subtle case. If it is really a problem, you may take a look into Rhinos code to see if the bug is easy to fix.