Wednesday, October 22, 2008

Rhino Mocks 3.5

I had a chance to upgrade to Rhino Mocks 3.5 recently. While I won't go over all of the new features I will go over the ones I have found most useful.

Static creation methods

CreateMock is deprecated. Use StrictMock instead. StrictMocks create brittle tests and therefore usage is discouraged. A better route is to forgo using an instance of a MockRepository altogether. Instead two static creation methods are available:
var mock = MockRepository.GenerateMock<IMock>(); // same as DynamicMock
var stub = MockRepository.GenerateStub<IStub>()
Compare with:
MockRepository mocks = new MockRepository();
IMock mock = mocks.DynamicMock<IMock>();
IStub stub = mocks.Stub<IStub>();
Note the terms "Mock" and "Stub" instead of DynamicMock and Stub. This is to be more in line with popular test double terminology which carries the benefit of being more intention revealing. Mocks should use Expect with constraints (using Arg<T>) before exercise of the unit-under-test (and VerifyAllExpectations after) or AssertWasCalled and AssertWasNotCalled after the exercise. Stubs should use the Stub method to return canned data which should be called before exercising the unit-under-test. Both Stub and Expect can be used on mocks, if you want to mix and match, but it makes the code less clear. Only Stub can be used on stubs. All properties on Stubs are defaulted to UsePropertyBehavior as with the old API. Note that Stubs cannot make the test fail.

Goodbye record-playback

The explicit phases of record and playback (and the using scopes along with them) is no longer necessary. The idea here is to simplify mocking. The new technique is called Arrange, Act, Assert or AAA for short.
  • Arrange - set up the unit under test
  • Act - exercise the unit under test, capturing any resulting state
  • Assert - verify the behavior through assertions
This is a long-winded way of saying exercise the unit under test and then verify the results, effectively making unit tests that use test doubles as succinct as those that don't.

Inline constraints
var view = MockRepository.GenerateMock<IPassiveView>();
// exercise unit-under-test
view.AssertWasCalled(x => x.SetSaveButtonState(
   Arg<string>.Matches(t => t.StartsWith("Saved")),
var view = MockRepository.GenerateMock<IPassiveView>();
view.Expect(x => x.SetSaveButtonState(
   Arg<string>.Matches(t => t.StartsWith("Saved")),
// exercise unit-under-test
This used to require creating a separate custom delegate for each different signature and then an assertion for each argument within the callback. The new syntax saves a lot of keystrokes. Note that with assertions no explicit verification is necessary. If there are expectations, they are to be verified on a per mock basis. This encourages using few mocks, however if multiple are used, the granularity of verification is smaller and cleaner. This was available in the previous API but had an uglier syntax before extension methods.

New event raising syntax

I find this new API call particularly useful with the PassiveView pattern to simulate the firing of UI events.
view.Raise(x => x.SaveClicked += null, view, EventArgs.Empty);
Compare with:
view.SaveClicked += null;
IEventRaiser buttonClick = LastCall.IgnoreArguments().GetEventRaiser();
buttonClick.Raise(view, EventArgs.Empty);
WhenCalled instead of CallBack

WhenCalled is a cleaner replacement for CallBack. It allows access to all of the arguments and the return value through the invocation object. It should not be used for validating arguments, use the Arg constraint instead. It is useful for keeping what is passed in or setting certain state when a particular method is called. For example:
var wasFired = false;
var buttonText = string.Empty;

view.Stub(x => x.SetSaveButtonText(Arg<string>.Is.Anything))
   .WhenCalled(invocation =>
         buttonText = (string)invocation.Arguments[0];
         wasFired = true;
The new 3.5 syntax is vastly superior to an already useful API. It is more succinct and expressive, lowering the barrier for entry and making code much more readable for the maintainer of the tests.

1 comment:

  1. Great post. I'm new with Rhino Mock.
    This is obsolutely much more readable.