29 Jun
2008

Looking at Rhino Mocks 3.5 (RC1)

Category:UncategorizedTag: :

I finally got some time to look into Rhino Mocks 3.5 to see what is new.  Lets say there are some interesting extensions to the library.  OK, that was a bad pun that you probably didn’t get.  A series of new extension methods were added.  Lets take a look.

Here is the list of some of the extension methods:

  • void AssertWasCalled<T>(this T mock, Action<T> action)
  • void AssertWasNotCalled<T>(this T mock, Action<T> action)
  • void BackToRecord<T>(this T mock)
  • IMethodOptions<VoidType> Expect<T>(this T mock, Action<T> action)
  • IList<object[]> GetArgumentsForCallsMadeOn<T>(this T mock, Action<T> action)
  • void Raise<TEventSource>(this TEventSource mockObject, Action<TEventSource> eventSubscription, params object[] args)
  • IMethodOptions<object> Stub<T>(this T mock, Action<T> action)

This is not a complete list, btw.  But these are the methods that I find interesting right now.  Plus, if you start looking at Ayende’s new samples, you will need to keep these in mind.  Speaking of Ayende’s samples, lets look at one.

   1: [Test]
   2: public void WhenUserForgetPasswordWillSendNotification_WithArgumentMatching()
   3: {
   4:     var userRepository = MockRepository.GenerateStub<IUserRepository>();
   5:     var notificationSender = MockRepository.GenerateStub<INotificationSender>();
   6:  
   7:     userRepository.Stub(x => x.GetUserById(5)).Return(new User { Id = 5, Name = "ayende" });
   8:  
   9:     new LoginController(userRepository, notificationSender).ForgotMyPassword(5);
  10:  
  11:     notificationSender.AssertWasCalled(x => x.Send("Changed password for ayende"));
  12: }

OK, first draw your attention to lines 4 and 5.  Note, there is nothing really new here.  We are creating a set of stub objects.  A stub object is a fake object that doesn’t care if you call it or not.  Now, I’m trying to draw your attention to these lines, because it makes lines 7 and 11 more interesting.

On to line 7.  userRepository.Stub.  userRepository is a stubbed object (see line 4), that I am betting does not have a method called Stub.  It is an extension method from Rhino Mocks.  Here is what the online documentation says the Sub method does:

Tell the mock object to perform a certain action when a matching method is called. Does not create an expectation for this method.

OK, so line 7 is telling userRepository that IF AND WHEN the userRepository method GetUserById is called for User 5, return a new User with an ID =5 and Name = “ayende”.   Before, this would have looked like this:

MockRepository.Stub(userRepository.GetUserById(5)).Return(….)

Now it is

userRepository.Stub( x => x.GetUserById(5).Return(….)

There is a similar Expect extension method that does create an expectation.

There is still room for misunderstanding with this new syntax, but it could be a step in the right direction.  One of the problems I’ve had with Rhino Mocks, and other Mocking frameworks is explaining the syntax to new users.  Namely, you don’t see the mock object you are testing against first, but the method Expect or Stub.  Now the object is out front.  This will still cause a few issues — especially for people who are not expecting extension methods, but I think that is just a small training issue.

Now on to line 11.

I’m looking at AssertWasCalled.  Note, this is called after the method ForgotMyPassword was called.  ForgotMyPassword is the method we are actually testing (also called the SUT, or system under test in unit testing lingo).

So, AssertWasCalled checks to see if the notification sender’s Send method was called, and fail the test if it wasn’t.  B-E-A-U-tiful.  This fixes one of the other major problems I’ve had explaining mocking, and it also made the tests harder to follow.  Here is why.

Typically in your test code you have two types of expectations.  Methods that you expect to call to get valuable information from so the SUT can continue, and methods that you expect to be called with that information.  Historically I’ve had to group both of those method calls together before the SUT is called.  That made things messy to me.  Plus things were all out of order.

The beauty of AssertWasCalled (and AssertWasNotCalled) is that they can be called AFTER the SUT is run.  Thus keeping everything in order and the coded easier to follow.

The big recap:

So here are the positive changes, as I see them:

  1. Mock/Stub objects come first when setting expectations
  2. You can check for values after the fact with AssertWasCalled and AssertWasNotCalled.

Thumbs up from me.

One thought on “Looking at Rhino Mocks 3.5 (RC1)”

Comments are closed.