In this article we’ll see difference between usage of MockRepository object initialization vs using Static functions to create and setup the mock/stubs. In the initial version of Rhino mocks it was the object which was being used but once the DynamicMock and Strick mocks becomes popular, new static function were being introduced in it’s release 3.5.
Readers Note: I’m expecting that if you’re reading this article you’re already familiar with Unit testing and requirements of Mock objects with basics of Rhino mocks.
Using the MockRepository concrete:
When we use the repository object to create and setup the expectations like:
var mocks = new MockRepository();
in this case when we start creating and setting up the expectations. The object automatically goes into the Record mode. and it won’t changes it’s state until you call PlayBack() or RelayAll() on repository object so to use the concrete object of repository you’ll be using it like below:
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("cshandler")).Return(theUser);
mockUserRepository.Expect( x => x.Save(theUser) );
}
using(mocks.Playback())
{
var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);
controllerUnderTest.ForgotMyPassword("cshandler");
}
}
Here we can see the Record block and Playback block are seperated out to keep the repository object separate from default behavior.
Now If you don’t want to use these block then the Static functions of MockRepository class will be your friend. Let’s have a look at the below snippet:
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("cshandler")).Return(theUser);
mockUserRepository.Expect( x => x.Save(theUser) );
var controllerUnderTest = new LoginController(mockUserRepository, stubbedSmsSender);
controllerUnderTest.ForgotMyPassword("cshandler");
mockUserRepository.VerifyAllExpectations();
}
This is quite easy to write and easily readable. Though there are differences between the usage.
If you are using the Instance then you don’t need to call the VerfiyAllExpectations() method while in case of without using the instance It is required to call this function explicitly. These two ways of using the mock/stub with Rhino mocks are standard. So be careful when you’re choosing any approach. Do not mix up both methodology or you’ll end up getting unexpected errors. I’m sharing a small check list which might help you when you start working with Rhino mocks.
Tips to remember while using Rhino mocks:
1. Stub() defines the behavior for stubbed object.
2. Expect() defines the behavior and the expectation for mocked object.
3. Follow the principle of "Test only one thing per test".
4. mockrepositoryObject doesn't stop recording until you call ReplayAll.
Try using repositoryInstance.PlayBack();
Code:
using (repository.Playback())5. Call repository.VerfiyAll() in the end.
{
}
6. Use strickMock for defined behavior and strict expectation for method and properties call.
7. use DynamicMock for object behavior testing for a data supplied.
More on Stub() and Mock(): 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. (see release notes 3.5 Rhino mocks)
8. Use following statement for debugging and detailed logging
RhinoMocks.Logger = new TextWriterExpectationLogger(Console.Out);
References: http://ayende.com/wiki/Rhino+Mocks+3.5.ashx
No comments:
Post a Comment