10

Is it possible to test for the following example if the Method1 called 1st, then Method2 called after and then Method3 by using the AAA syntax, in 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());
pencilCake
  • 51,323
  • 85
  • 226
  • 363

5 Answers5

19

Here's one way to do it...

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());
Brandon Joyce
  • 3,100
  • 24
  • 25
9

You can, but you really shouldn't. You should focus on testing the externall observable behaviors, rather than the implementation.

Method call order can change without affecting the contract with the client of the API. In that case, your test will fail, even when it shouldn't.

In short, testing implementation leads to brittle tests. Brittle tests lead to abandonment of the tests. You don't want to go there.

Hope this helps.

Assaf Stone
  • 6,309
  • 1
  • 34
  • 43
  • 19
    This is not always the case. There are contracts of statefull objects where ordering matters and you can not always avoid those contracts. – sanosdole Jun 23 '12 at 16:02
  • I agree with the comment by @sanosdole but in my case you were spot on. I should be testing the result...not the implementation. Thanks! – MoMo Mar 20 '14 at 20:07
  • If code already has temporal coupling it also should be tested. – SerG Oct 03 '17 at 10:29
5

Here is how to do it nicely.

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

Found the answer from this blog post: Verifying the Order Of Method Execution With Rhino Mocks 3.5 by Philip Japikse

Dan Stevens
  • 6,392
  • 10
  • 49
  • 68
craastad
  • 6,222
  • 5
  • 32
  • 46
1

Here's how to do it by building assertions into each method invocation.

// 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());

Since this is mixes up normal arrange-act-assert pattern by running assertions in mid-act, I like to include very specific error messages for these instances to identify test failures more easily.

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

You could also achieve a similar result by saving the result of each invocation in a variable during the act step, and then checking the variable states during the assert step. This better preserves the division of the arrange-act-assert pattern, but it is more plumbing code to write and maintain.

// 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.");
Drew Spickes
  • 234
  • 2
  • 7
0

The mocks.Ordered() syntax specified by @craastad is the right way to do it, but I couldn't get it to work in RhinoMocks 3.5 - instead I had to tweak it to work without the instance of MockRepository that @craastad's solution used to call Ordered() on:

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

If you do it this way, it also appears to be unnecessary to call fooMock.Replay() either.

Clarkeye
  • 889
  • 8
  • 9
  • 3
    Someone marked this answer down, which is fair enough, but if you're going to do that then the least that you could is explain why! – Clarkeye Apr 25 '16 at 09:44