Могу ли я проверить порядок вызова метода с синтаксисом AAA в Rhino-Mocks 3.6?

Можно ли проверить следующий пример, если Method1 называется 1st, затем Method2 вызывается после, а затем Method3, используя синтаксис AAA, в Rhino-mocks 3.6?

// Assert
var mock = MockRepository.GenerateMock<ISomeService>();

// Act
myObject.Service = mock;

// How should I change this part to ensure that Rhino Mocks check the call order as well?
mock.AssertWasCalled(m=>m.Method1());
mock.AssertWasCalled(m=>m.Method2());
mock.AssertWasCalled(m=>m.Method3());

Ответ 1

Вот один из способов сделать это...

mock.AssertWasCalled(m=>m.Method1(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method2())));
mock.AssertWasCalled(m=>m.Method2(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method3())));
mock.AssertWasCalled(m=>m.Method3());

Ответ 2

Вы можете, но вы действительно не должны. Вы должны сосредоточиться на тестировании внешнего наблюдаемого поведения, а не на реализации.

Порядок вызова метода может измениться, не затрагивая контракт с клиентом API. В этом случае ваш тест завершится неудачно, даже если это не так.

Короче говоря, тестирование тестирования приводит к хрупким испытаниям. Хрупкие тесты приводят к отказу от тестов. Вы не хотите туда идти.

Надеюсь, что это поможет.

Ответ 3

Вот как это сделать.

var mocks = new MockRepository();
var fooMock = mocks.DynamicMock<IFoo>();
using (mocks.Ordered())
{
    fooMock.Expect(x => x.Method1());
    fooMock.Expect(x => x.Method2());
}
fooMock.Replay();

var bar = new Bar(fooMock);
bar.DoWork();

fooMock.VerifyAllExpectations();

Нашел ответ из этого блога.

Ответ 4

Здесь, как это сделать, создавая утверждения в каждом вызове метода.

// Arrange - Build the necessary assertions into the stubbed method invocations.
var mock = MockRepository.GenerateMock<ISomeService>();
mock.Stub(m => m.Method1()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method2()));
mock.Stub(m => m.Method2()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method3()));

// Act
myObject.Service = mock;

// Assert - Ensure each expected method was called.
mock.AssertWasCalled(m => m.Method1());
mock.AssertWasCalled(m => m.Method2());
mock.AssertWasCalled(m => m.Method3());

Так как это смешивает нормальный шаблон arr-act-assert, запуская утверждения в середине действия, мне нравится включать очень конкретные сообщения об ошибках для этих экземпляров, чтобы легче выявлять тесты.

mock.Stub(m => m.Method1()).WhenCalled(inv =>
    mock.AssertWasNotCalled(m => m.Method2(), opt =>
        opt.Message("Method2 cannot be called before Method1.")));

Вы также можете добиться аналогичного результата, сохранив результат каждого вызова в переменной во время шага действия, а затем проверив состояния переменных во время шага assert. Это лучше сохраняет разделение шаблона arr-act-assert, но для написания и поддержания более строгих правил написания и обслуживания.

// Arrange - Build the necessary state variables into the stubbed method invocations.
bool wasMethod1Called;
bool wasMethod2Called;
bool wasMethod2CalledBeforeMethod1;
bool wasMethod3CalledBeforeMethod2;

var mock = MockRepository.GenerateMock<ISomeService>();
mock.Stub(m => m.Method1()).WhenCalled(inv =>
{
    wasMethod1Called = true;
});
mock.Stub(m => m.Method2()).WhenCalled(inv =>
{
    wasMethod2Called = true;
    wasMethod2CalledBeforeMethod1 = !wasMethod1Called;
});
mock.Stub(m => m.Method3()).WhenCalled(inv =>
{
    wasMethod3CalledBeforeMethod2 = !wasMethod2Called;
});

// Act
myObject.Service = mock;

// Assert - Ensure each expected method was called, and that they were called in the right order.
mock.AssertWasCalled(m => m.Method1());
mock.AssertWasCalled(m => m.Method2());
mock.AssertWasCalled(m => m.Method3());
Assert.That(wasMethod2CalledBeforeMethod1, Is.False, "Method2 cannot be called before Method1.");
Assert.That(wasMethod3CalledBeforeMethod2, Is.False, "Method3 cannot be called before Method2.");

Ответ 5

Синтаксис mocks.Ordered(), указанный @craastad, - это правильный способ сделать это, но я не мог заставить его работать в RhinoMocks 3.5 - вместо этого мне пришлось настроить его, чтобы работать без экземпляра MockRepository, который @Решение craastad, используемое для вызова Ordered():

var fooMock = MockRepository.GenerateMock<IFoo>();
using (fooMock.GetMockRepository().Ordered())
{
    fooMock.Expect(x => x.Method1());
    fooMock.Expect(x => x.Method2());
}

var bar = new Bar(fooMock);
bar.DoWork();

fooMock.VerifyAllExpectations();

Если вы это сделаете, вам также необязательно вызывать fooMock.Replay().