Monday, 8 April 2013

Implementing TDD with Rhino Mocks



In Testing: What are Mock objects and why do we need them?

When implementing unit test you might encounter a common problem: the object you want to unit-test can only exist in conjunction with other objects, and to build these objects (a.k.a. dependencies) you might need to go through a different algorithm that is outside of your scope. If you decide to go ahead and create these dependencies in the standard manner your unit test might turn gradually into an “integration test”.  Mock objects provide a workaround for such cases by making unit test maintainable and readable. The power of mock objects is that you have a reflection of the methods that mocked objects receive, so for example you can write testing code that verifies that a method on one object is only called after a method on another object has been called.

What is Rhino Mocks


Rhino Mocks helps you create stubs for objects in your code that you can use to simulate various situations. This is useful for skipping a long process that will result in creating a full instance of the object you want to mock.
Rhino Mocks belongs to a family of APIs called “Mock Object Frameworks”.  Similar APIs include: NMock, EasyMock.NET, TypeMock Isolator, Moq, NSubstitute, JustMock, FakeItEasy, Microsoft Fakes (formerly Moles, included with VS 2012 Ultimate)
 There is a very useful free e-book about RhinoMocks here

RhinoMocks concepts

The following concepts are the building blocks behind RhinoMocks:


Mock Object

An object that pretends to be another object and allows you to set expectations on its 
interactions with another object.

Difference between Mock object & Stub

The main difference is that a mock is an object you can set expectations on. You can still setup expectations on the stub object, but those expectations will never be verified. So a mock is a more involved type of stubs where you have a mechanism to ensure a certain sequence of function calls happened. For example, i.e. the mock framework provides you with a monitor on the messages (methods) that the mocked object receives. If you just want to pass a value to make you code act in a certain way, you can use a stub. Both types of objects are provided by the RhinoMocks framework as you can see in the examples below.

State-based testing (a.k.a. AAA model – Arrange, Act, Assert)

Initiate an action and then check that the expected results (return value, property, created object, etc…) are maintained.  More on this in the “RhinoMocks AAA model” section below.

Expectation

Validation that a particular method call is the expected step.

Ordering

The API should be able to specify that replaying a sequence of method calls will happen in a specific order

Record & Replay model: (a.k.a Interaction-based testing)

In the testing model used for earlier version of RhinoMocks. It basically says that there are two semantic units in your test code: Record and Replay. This is illustrated in the RhinoMocks Basic Usage section.

RhinoMocks Basic Usage

 1.       Create a mock repository
MockRepository mocks = new MockRepository();
This is the mock objects factory. It is used to create mock objects

2.       Instantiate a mock object using the repository
ISomeInterface robot = mocks.CreateMock<ISomeInterface>();

3.       “Record” the methods you expect to be called on the mock object
// this method has a return type, so wrap it with Expect.Call
Expect.Call(robot.SendCommand("Wake Up")).Return("Groan");

// this method has void return type, so simply call it
robot.Poke();
// when no return type, any extra information about the method call
// is provided immediately after via static methods on LastCall
LastCall.On(robot).Repeat.Twice();

//Set the mock object to a "Replay" state where, as called, it will replay the operations just recorded.
mocks.ReplayAll();
The first line above tells the framework that the client code should invoke SendCommand(“Wake Up”) on the mock object, which should return the string “Groan”, while the second line tells the framework that the client code should invoke the method Poke() on the mock object. The parameters we send to the Mock object and the return values are part of the test.

4.       Now that you have recorded the call sequence that should be implemented inside the client method call, invoke this client method call and verify that these interactions with the mock object take place. This is the “Replay” part
theButler.GetRobotReady();
//Check that all calls were made to the mock object.
mocks.VerifyAll();



RhinoMocks AAA model


The AAA (Arrange, Act, Assert) is a new syntax standardization that was released starting with Rhino Mocks 3.5. In this test model you arrange the state, then execute the code given the state, and then assert that the expected state change has happened.
Here is an example that illustrates AAA from the official blog:
Let’s say this is the class that we want to test (i.e. the client code that interacts with the mock object)

public class LoginController
{
    private readonly IUserRepository repository;
    private readonly INotificationSender sender;

    public LoginController(IUserRepository repository, INotificationSender sender)
    {
        this.repository = repository;
        this.sender = sender;
    }

    public void ForgotMyPassword(int userId)
    {
        User user = repository.GetUserById(userId);
        sender.Send("Changed password for " + user.Name);
    }
}

Now this is the test for the method ForgotMyPassword(), mocking the INotificationSender object:
public void TestForgotMyPassword()
{
    var userRepository = MockRepository.GenerateStub<IUserRepository>();
    var notificationSender = MockRepository.GenerateMock<INotificationSender>();

    userRepository.Stub(x => x.GetUserById(5)).Return(new User { Id = 5, Name = "ayende" });
    notificationSender.Expect(x => x.Send(null)).Constraints(Text.StartsWith("Changed"));

    new LoginController(userRepository, notificationSender).ForgotMyPassword(5);

    notificationSender.VerifyAllExpectations();
}
Notice that for the other object we interact with (IUserRepository), we only used the Stub() method for it and not a mock methods like Expect(). This means we are not interested in monitoring what calls are sent to it, we only care that this object would have the properties specified in the stub we created in the test. While for the INotificationSender object we need to make sure that the method Send() is invoked on it, with a string that begins with “Changed”.
More is available about the difference between the Expect() and Stub() methods here.

This is another test that uses a syntax that is more readable (a lambda expression for the Send() method parameters):
public void WhenUserForgetPasswordWillSendNotification_WithArgMatchingInTheLambda()
{
    var userRepository = MockRepository.GenerateStub<IUserRepository>();
    var notificationSender = MockRepository.GenerateStub<INotificationSender>();

    userRepository.Stub(x => x.GetUserById(5)).Return(new User { Id = 5, Name = "ayende" });

    new LoginController(userRepository, notificationSender).ForgotMyPassword(5);

    notificationSender.AssertWasCalled(x =>
        x.Send(Arg<string>.Matches(s => s.StartsWith("Changed"))));
}

The syntax above explicitly states that the call to Send() receives a string parameter that starts with “Changed”.
More tests can be found here. What can be seen in the couple of tests above is that we set the state first (the user with Id = 5), and then we do the action ForgotMyPassword() with Id 5; and finally we Assert the methods that return a stub and send a notification are called.

No comments:

Post a Comment