AssertWasCalled и Stub с методом, который имеет параметр ref - PullRequest
2 голосов
/ 15 апреля 2011

У меня проблемы с заглушкой метода с параметром 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));

Кстати: я знаю, что этот тест не имеет никакого смысла, потому что он не проверяет никаких реальных классов.Это сжатая версия моего реального теста, чтобы проиллюстрировать проблему.

Как видите, происходит нечто странное:

Заглушка метода execute правильная и она вызывается,потому что executeCalled равен 1, а параметр tmp был изменен с inputValue на outputValue.
НО:

  • Первая проверка с AssertWasCalled проходит , хотя он проверяет, был ли вызван Execute с outputValue , чего не было.
  • Вторая проверка с AssertWasCalled завершается неудачей , хотяон проверяет, был ли Execute вызван с inputValue , что и было.

Кроме того, когда я проверяю i.Arguments[1] внутри WhenCalled заглушки, это outputValue, а не inputValue ... Похоже, что Rhino Mocks изменяет входное значение на указанное возвращаемое значение, даже не вызывая заглушку ...

Является ли это ошибкой в ​​Rhino Mocks?Или я что-то упустил?Если это ошибка, есть ли обходные пути, кроме счетчика executeCalled?

1 Ответ

2 голосов
/ 19 апреля 2011

Тот же тест, немного прибрано:

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

Это можно рассматривать как ошибку, но это довольно тонкий случай. Если это действительно проблема, вы можете взглянуть на код Rhinos, чтобы узнать, легко ли исправить ошибку.

...