Ayende @ Wiki

Method calls in Rhino Mocks can be ordered or unordered. The default state for a recorder is unordered recording, this means that during replay, methods can come at any order. If the recorder is changed to ordered, then the methods must be called in the exact same order as they were recorded. Here is a code sample:

[Test]
public void SaveProjectAs_NewNameWithoutConflicts()
{
  using(mocks.Ordered())
  {
    Expect.Call(projectView.Title).
      Return(prj.Name);
    Expect.Call(projectView.Ask(question,answer)).
      Return( newProjectName);
    Expect.Call(repository.GetProjectByName(newProjectName)).
      Return(null);
    projectView.Title = newProjectName;
    projectView.HasChanges = false;
    repository.SaveProject(prj);
  }
  mocks.ReplayAll();
  Assert.IsTrue(presenter.SaveProjectAs());
  Assert.AreEqual(newProjectName,prj.Name);
}


In the above code example we ask Rhino Mocks to verify that the calls come in the exact same order. Notice that we specify expectations on several mock objects, and Rhino Mocks will handle the ordering between them. This mean that if I set the project view title before I get a project from the repository, the test will fail. In Rhino Mocks, the default is to use unordered matching, but it supports unlimited depth of nesting between ordered and unordered. This means that you can create really powerful expectations. Here is a somewhat contrived example:

[Test]
public void MovingFundsUsingTransactions()
{
  MockRepository mocks = new MockRepository();
  IDatabaseManager databaseManager = mocks.StrictMock<IDatabaseManager>();
  IBankAccount accountOne = mocks.StrictMock<IBackAccount>(),
               accountTwo = mocks.StrictMock<IBackAccount>(); 
  using(mocks.Ordered())
  {
     Expect.Call(databaseManager.BeginTransaction()).Return(databaseManager);
     using(mocks.Unordered())
     {
        Expect.Call(accountOne.Withdraw(1000));
        Expect.Call(accountTwo.Deposit(1000));
     }
     Expect.Call(databaseManager.Dispose());
  }
  mocks.ReplayAll();
  Bank bank = new Bank(databaseManager);
  bank.TransferFunds(accountOne,accountTwo,1000);
  mocks.VerifyAll();
}


This code verifies that the transfer of funds from one account to another is wrapped in a transaction, but the implementation is free to withdraw from the first account first, or to deposit into the second account first, both are legal, as long as both actions happens. The reverse is true as well, you may specified unordered sequence of ordered events (I want A then B then C to happen, and I want D then E then F to happen, but I don't care which sequence comes first).

Ordering has two caveats:

  • To exit an ordering in replay state, you must call all the recorded methods. In the above example, we can move from the inner Unordered ordering (the one containing the withdraw and deposit) only after both methods were called. This falls in line with the way the recording code looks, so it shouldn't cause any surprises.
  • You must exit all ordering before you can start replaying. This is enforced by the framework (you get an exception if you try).

Up: Rhino Mocks Documentation
Next: Rhino Mocks Mocking Delegates

ScrewTurn Wiki version 2.0 Beta. Some of the icons created by FamFamFam.