Ayende @ Wiki

Page History: Rhino Mocks 3.5


Compare Page Revisions



« Older Revision - Back to Page History - Newer Revision »


Page Revision: 2008/08/12 17:36


Rhino Mocks 3.5 introduce some new concepts, mostly by building on top of the language features of C# 3.0. User on the 2.0 platform needs not to worry, there are enough goodies for them as well (inline constraints, for example), but the focus of this document is on documenting the use of Rhino Mocks using C# 3.0.



Edit

What's New in Rhino Mocks 3.5

New things in Rhino Mocks 3.5:

  • Arrange, Act, Assert model
  • Lambda and C# 3.0 extensions
  • Inline constraints
  • Support for mocking interface in C++ that mix native and managed types.
  • Allow a mock object to return to record mode without losing its expectations
  • CreateMock was deprecated in favor of StrictMock
  • Better error handling in edge cases.
  • Fixed an issue with mocking internal classes and interfaces
  • New event raising syntax

Edit

Usage Guidance

In general, I recommend following the "Test only one thing" per test. As such, the recommended approach for using Rhino Mocks (and mocking in general) is composed of a single mock object per test and several stubs (as needed).

Edit

The difference between stubs and mocks

You can get the actual definition of the these terms in this article: Mocks Aren't Stubs. I want to focus on the difference from the point of view of Rhino Mocks.

A mock is an object that we can set expectations on, and which will verify that the expected actions have indeed occurred. A stub is an object that you use in order to pass to the code under test. You can setup expectations on it, so it would act in certain ways, but those expectations will never be verified. A stub's properties will automatically behave like normal properties, and you can't set expectations on them.

If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.

IMPORTANT: A stub will never cause a test to fail.


Let us create a sample test, which will give us more context to talk about. We want to write a test for sending an SMS for a forgotten password. The code should:
  • Get the user from the repository
  • Reset the password to a random one
  • Save the user with the new password
  • Send an SMS with the new password

Note that I am using the new syntax here which will be explained shortly


First, we want to test that we reset the password, so we will write the following test:

public void When_user_forgot_password_should_reset_password()
{
    var stubUserRepository = MockRepository.GenerateStub<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};

stubUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

var controllerUnderTest = new LoginController(stubUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende");

Assert.AreNotEqual("this is not hashed password", theUser.HashedPassword); }


In this test, we have created two stubs, passed them to the code under test, and asserted that the password was changed. To make this code pass we can use:

public void ForgotMyPassword(string username)
{
   var user = users.GetUserByName(username);
   user.HashedPassword = "new pass";
}


Now we want to verify that the user will save the password, so we have the following test:

public void When_user_forgot_password_should_save_user()
{
    var mockUserRepository = MockRepository.GenerateMock<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};

mockUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

mockUserRepository.Expect( x => x.Save(theUser) );

var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende");

mockUserRepository.VerifyAllExpectations(); }


Now we have used a mock object and set an expectations on it. Note that even though we are using a mock object here, we are still stubbing the call to GetUserByName. We don't care about this, since this is not what we are testing.

The code under test now looks like:

public void ForgotMyPassword(string username)
{
   var user = users.GetUserByName(username);
   user.HashedPassword = "new pass";
   users.Save(user);
}


Another way to write the test would have been:

public void When_user_forgot_password_should_reset_password()
{
    var stubUserRepository = MockRepository.GenerateStub<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};

stubUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

var controllerUnderTest = new LoginController(stubUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende");

stubUserRepository.AssertWasCalled( x => x.Save(user)); }


We have no expectations in this test, just setting the required state and asserting on the actions that occurred when the code under test run. The difference between the two test is subtle, but important. In most cases, you should prefer to use stubs. Only when you are testing complex interactions would I recommend to use mock objects. If you need to ensure ordering, or expect to get a complex method, or want to ensure an exact adherence to the expectations.

Note that so far, we haven't even cared about the actual sending on an SMS, let us write a test that ensure that we can send an SMS.

public void When_user_forgot_password_should_reset_password()
{
    var stubUserRepository = MockRepository.GenerateStub<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password", Phone = "1234-1234"};

stubUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

var controllerUnderTest = new LoginController(stubUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende");

stubbedSmsSender.AssertWasCalled( x => x.Send( Arg.Is.Eqaul("1234-1234"), Arg.Text.StartsWith("Password was changed to:") )); }


Here we are asserting that the method was called, and use the inline constraint support to ensure we pass the correct arguments. The code under test now looks like:

public void ForgotMyPassword(string username)
{
   var user = users.GetUserByName(username);
   user.HashedPassword = "new pass";
   users.Save(user);
   smsSender.Send(user.Phone, "Password was changed to: new pass");
}


It is important to remember that we don't want to be tied down by our tests. We want to make sure that even if we modify the code under test, we will not break any unrelated tests.

Edit

CreateMock is deprecated, replaced by StrictMock. The use of Strict Mock is discouraged.

In Rhino Mocks 3.4 and previous, the "default" way to get a mock object was to call mockRepository.CreateMock<ISmsSender>(). That caused a very serious issue. CreateMock() would return a strict mock, and as we have already discussed, an overly strict mock will create a brittle test. As a result of that, CreateMock() was deprecated and will generate a compiler warning if used. You can replace calls to CreateMock() with StrictMock(). However, using StrictMock() is discourage. Strict mocks will fail if something that is not expected will happen to them. In the long run, this means that any change to the code under test can break your tests, even if the change has nothing to do with what you are actually testing in this specific test.

I encourage the use of stubs and dynamic mocks instead.

Edit

Mocking with and without an instance of MockRepository

Rhino Mocks 3.5 introduce a new mode of mocking, using mocks without creating the repository. The purpose of that is to reduce the amount of book keeping that you have to do. Here is a test without the repository:

public void When_user_forgot_password_should_save_user()
{
    var mockUserRepository = MockRepository.GenerateMock<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};

mockUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

mockUserRepository.Expect( x => x.Save(theUser) );

var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende");

mockUserRepository.VerifyAllExpectations(); }


With a repository, the test would look like:

public void When_user_forgot_password_should_save_user()
{
	var mocks = new MockRepository();
        var mockUserRepository = mocks.DynamicMock<IUserRepository>();
        var stubbedSmsSender = mocks.GenerateStub<ISmsSender>();

using(mocks.Record()) { var theUser = new User{HashedPassword = "this is not hashed password"};

mockUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

mockUserRepository.Expect( x => x.Save(theUser) ); } using(mocks.Playback()) {

var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende"); } }


There are a few other differences between the two approaches:
  • Mocks/stubs returned from MockRepository.GenerateMock() and MockRepository.GenerateStub() are returned in replay mode, and do not require explicit move to replay mode.
  • Only Dynamic Mocks and Stubs are available without creating the repository. (This is done under the assumption that those are the most commonly used, and deserve their shortcut).
  • Without creating a repository, you need to call VerifyAllExpectations() on each of the mock objects that you created. If you have a repository, you can simply call VerifyAll() on the repository and it will do the work for you. Since in most situations you will have only a single mock per test (and stubs require no verifications), that is not an issue.

Edit

Arrange, Act, Assert

The major feature in Rhino Mocks 3.5 is the AAA syntax. Arrange, Act, Assert is a classic way to setup your tests. First you arrange the state, then you execute the code under test, finally you assert that the expected state change happened. With interaction based testing, this was generally impossible, and required that you would use the Record/Replay model. This was a common case for confusion for people new to interaction based testing. The AAA syntax solve this problem.

Let us take a look at a simple test and analyze it using the AAA approach:

public void When_user_forgot_password_should_reset_password()
{
    // arrange
    var stubUserRepository = MockRepository.GenerateStub<IUserRepository>();
    var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};

stubUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser); // act var controllerUnderTest = new LoginController(stubUserRepository, stubbedSmsSender);

controllerUnderTest.ForgotMyPassword("ayende");

// assert stubUserRepository.AssertWasCalled( x => x.Save(user)); }


We can easily see the different stages of the test. The main supporters for this method of operation are the Expect() and Stub() methods.

Edit

Expect and Stub Extension Methods

The Expect() and Stub() methods are extension methods that become available for use on any mock object when you reference (using in C# or Imports in VB.NET) the Rhino.Mocks namespace.

Edit

Expect() Extension Method

The Expect() extension method creates a new expectation for this mock which must be verified/asserted later (using either the VerifyAllExpectations() or AssertWasCalled() methods).

Expect() functions similarly to the Expect.Call() functionality from previous versions of Rhino Mocks, except the .Expect() extension method can be used without a Record() block (whereas Expect.Call() must be called from within an explicit Record() block).

Consider the following example usage which ensures that the controller SignOut action calls the authSvc's SignOut method:

Test
public void should_sign_out_of_the_auth_service_when_the_logout_action_is_invoked()
{
	IAuthService authSvc = MockRepository.GenerateMock();

authSvc.Expect(svc => svc.SignOut()).Return(true);

SignoutControllercontroller = new SignoutController(authSvc); controller.SignOut();

authSvc.VerifyAllExpectations(); }


Edit

Stub() Extension Method

The Stub() extension method will stub a specific member so that it will perform the default stub behavior (i.e. not fail the test -- for specific behavior, please see definition of stub earlier in this document) for that particular member.

Consider the following example which is the same as the previous example, but includes an unrelated dependency that may need to be satisfied in order to test the functionality in which we're interested:

Test
public void should_sign_out_of_the_auth_service_when_the_logout_action_is_invoked()
{
	IAuthService authSvc = MockRepository.GenerateMock();
	IUnrelatedDependency otherDependency = MockRepository.GenerateMock();

otherDependency.Stub(o => o.UserIsLoggingOut()); authSvc.Expect(svc => svc.SignOut()).Return(true);

SignoutController controller = new SignoutController(authSvc, otherDependency); controller.SignOut();

authSvc.VerifyAllExpectations(); }


Edit

What is the difference between GenerateStub and GenerateMock

GenerateMock() is equivalent to calling DynamicMock() on a MockRepository instance in previous versions of Rhino Mocks. GenerateMock will create a dynamic mock (as opposed to a static mock or stub).

GenerateStub() is equivalent to calling Stub() on a MockRepository instance in previous versions of Rhino Mocks. GenerateStub will create a stubbed instance which will have stub behavior (see earlier in this article for the definition of Stub and explanation of Stub semantics).

Edit

Using the AAA syntax in C# 2.0

Edit

How to raise events

Rhino Mocks 3.5 introduces a new way of raising events from mocks. Prior to 3.5 this was generally done via the IEventRaiser interface like this:

[Test]
public void RaisingEventOnView()
{
   IView view = mocks.CreateMock();
   view.Load+=null;//create an expectation that someone will subscribe to this event
   LastCall.IgnoreArguments();// we don't care who is subscribing
   IEventRaiser raiseViewEvent = LastCall.GetEventRaiser();//get event raiser for the last event, in this case, View

mocks.ReplayAll();

Presenter p = new Presenter(view); raiseViewEvent.Raise();

Assert.IsTrue(p.OnLoadCalled); }


Rhino Mocks 3.5 provides some extension methods to make this a bit easier:

[Test]
public void RaisingEventOnViewUsingExtensionMethod()
{
   IView view = mocks.CreateMock();
   Presenter p = new Presenter(view);

view.Raise(x => x.Load += null, this, EventArgs.Empty);

Assert.IsTrue(p.OnLoadCalled); }


The Raise() extension method takes a subscription to the event you want raised (view.Load in this case, as per the x => x.Load += null subscription), the event sender, and the arguments for the event.

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