开发者

AssertWasCalled and Stub with method that has ref parameter

开发者 https://www.devze.com 2023-02-25 04:49 出处:网络
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.

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 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.

BUT:

  • The first check with AssertWasCalled passes, although it checks, whether Execute was called with outputValue, which it wasn't.
  • The second check with AssertWasCalled failes, although it checks, whether Execute 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号