AssertWasCalled и Stub с методом, который имеет параметр ref
У меня есть проблемы с заглушкой метода с 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 ответ
Тот же тест, немного подчищенный:
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, чтобы увидеть, легко ли исправить ошибку.