AssertWasCalled and Stub with method that has ref parameter
I have problems with stubbing a method with a ref
parameter.
// 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 con开发者_如何学Pythondensed 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
.
- 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:
public interface IX
{
void Execute(ref object param);
}
[TestMethod]
public void TestMethod()
{
// Variables needed - can be skipped
var inputValue = new object();
var outputValue = new object();
IX activity = MockRepository.GenerateMock<IX>();
// The stub:
activity
.Stub(x => x.Execute(
ref Arg<object>.Ref(Is.Same(inputValue), outputValue).Dummy));
var tmp = inputValue;
activity.Execute(ref tmp);
activity
.AssertWasCalled(x => x.Execute(
ref Arg<object>.Ref(Is.Same(outputValue), null).Dummy));
}
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:
[TestMethod]
public void TestMethod()
{
// Variables needed - can be skipped
var inputValue = new object();
var outputValue = new object();
IX activity = MockRepository.GenerateMock<IX>();
// The stub:
activity
.Stub(x => x.Execute(
ref Arg<object>.Ref(Is.Same(inputValue), outputValue).Dummy));
activity.Execute(ref inputValue);
activity
.AssertWasCalled(x => x.Execute(
ref Arg<object>.Ref(Is.Same(inputValue), null).Dummy));
}
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.
精彩评论