AssertWasCalled和Stub的方法有ref参数

本文关键字:ref 参数 方法 Stub AssertWasCalled | 更新日期: 2023-09-27 17:50:11

我在使用ref参数存根方法时遇到了问题。
我想为某个输入值存根这个方法,并检查它是否被调用。
我的尝试:

// 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:我知道,这个测试没有任何意义,因为它没有测试任何真正的类。这是我的真实测试的浓缩版本,以说明这个问题。

你可以看到,有一些奇怪的事情发生了:

execute方法的存根是正确的,因为executeCalled为1,而tmp参数从inputValue改为outputValue
但是:

  • 第一次检查AssertWasCalled 通过,尽管它检查Execute是否被outputValue调用,但它不是。
  • 第二次检查AssertWasCalled 失败,尽管它检查了Execute是否被inputValue调用,

此外,当我在存根的WhenCalled中检查i.Arguments[1]时,它是outputValue,而不是inputValue…看起来Rhino Mocks甚至在调用存根之前就将输入值更改为指定的返回值…

这是Rhino mock中的一个bug吗?还是我错过了什么?如果这是一个错误,有任何解决方案,旁边的executeCalled计数器?

AssertWasCalled和Stub的方法有ref参数

同样的测试,稍微清理一下:

    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));
    }

它是正确的。它清楚地表明Rhino记录了输出值,而不是原始输入值。它很少被识别出来,因为您需要这个临时变量来测试这种效果。

下面的测试也通过了:

    [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));
    }

这可以看作是一个bug,但却是一个非常微妙的例子。如果这确实是一个问题,您可以查看一下rhino代码,看看这个bug是否容易修复。