Как правильно использовать Rhino.Mocks AssertWasCalled()?
Я вызываю _mocks.ReplayAll()
, затем один или несколько _mockedObject.AssertWasCalled()
, а затем _mocks.VerifyAll()
. Но он говорит мне, что "это действие недействительно, когда макет объекта находится в состоянии записи".
[Test]
public void SetStateExecuting_Should_Set_State_To_Pause_And_Not_Change_GlobalState_When_GlobalState_Is_Paused()
{
var task = new Task { ID = 1, TimeZone = -660, GlobalState = TaskState.Paused };
_taskDataProvider.Expect(p => p.StateUpdate(task.ID, task.TimeZone, TaskState.Paused));
_mockRepository.ReplayAll();
_manager.SetStateExecuting(task);
_taskDataProvider.AssertWasNotCalled(p => p.GlobalStateUpdate(task.ID,
TaskState.Executing));
_mockRepository.VerifyAll();
}
Каков правильный порядок вызова, чтобы эти методы работали правильно?
Ответы
Ответ 1
Сообщение Джона Крюгера "Как использовать носороги, задокументированные в тестах" содержит простые примеры всего, что вы можете сделать с методами ноу-хаусов. Он также показывает, что вы не можете сделать, что я нашел очень полезным в обучении.
Как упоминалось ранее, использование упрощенного, Act, Assert синтаксиса со статическими конструкторами легче читать. В блоге показаны примеры обоих методов.
Вот примеры из примера кода Jon:
Новый синтаксис:
[Test]
public void You_can_check_to_see_if_a_method_was_called()
{
var stub = MockRepository.GenerateStub<ISampleClass>();
stub.MethodThatReturnsInteger("foo");
stub.AssertWasCalled(s => s.MethodThatReturnsInteger("foo"));
stub.AssertWasCalled(s => s.MethodThatReturnsInteger(Arg<string>.Is.Anything));
}
Старый стиль:
[Test]
public void Calling_virtual_methods_will_call_the_actual_method()
{
var mockRepository = new MockRepository();
var sampleClass = mockRepository.PartialMock<SampleClass>();
sampleClass.Replay();
sampleClass.VirtualMethod("foo").ShouldEqual(3);
sampleClass.VirtualMethodWasCalled.ShouldBeTrue();
sampleClass.AssertWasCalled(c => c.VirtualMethod("foo"));
}
Ответ 2
Вы смешиваете старый шаблон записи/воспроизведения и новый шаблон AAA.
Обычный способ настройки ожидаемого "не вызываемого с этими аргументами" в режиме записи выглядит следующим образом:
_taskDataProvider.Expect(
p => p.GlobalStateUpdate(task.ID, TaskState.Executing)).Repeat.Never();
Или, альтернативно, вы можете использовать строгий макет, который просто не разрешает неожиданные вызовы.
AssertWasCalled
и AssertWasNotCalled
предназначены для AAA, где вы ставите свои утверждения в конце. С синтаксисом Record/Replay, как поведение, так и исходы должны быть настроены в начале, прежде чем переключиться в режим воспроизведения.
(AssertWasNotCalled
может работать с Record/Replay также, но я никогда не пробовал, потому что мне не нравится смешивать элементы с обоих подходов. Это неудобно усложняет ситуацию.)
Ответ 3
Похоже, я нашел решение. Кажется немного странным, но это работает. Оказывается, мне нужно вызвать ReplayAll() дважды по какой-то причине...
Это работает:
[Test]
public void SetStateExecuting_Should_Set_State_To_Pause_And_Not_Change_GlobalState_When_GlobalState_Is_Paused()
{
var task = new Task { ID = 1, TimeZone = -660, GlobalState = TaskState.Paused };
_mockRepository.ReplayAll();
_manager.SetStateExecuting(task);
_taskDataProvider.AssertWasCalled(p => p.StateUpdate(task.ID, task.TimeZone, TaskState.Paused));
_taskDataProvider.AssertWasNotCalled(p => p.GlobalStateUpdate(task.ID, TaskState.Executing));
_mockRepository.ReplayAll();
}