Nov 2, 2013

Rhino Mocks–what is it

Rhino Mocks, the mocking framework, appeared at 2005. It hasn’t had any changes for two years and author announced that he will not support the project anymore. Then, there was a guy who decided to continue development of Rhino Mocks. I took a look at source code – he would definitely have what to change and improve. Code is abandoned, documentation is almost absent.
Here, the last update.

Rhino Mocks has been created on top of Castle Proxy. It could mock anything, that could be substituted with inheritance (virtual class members only).
Historically, the framework targeted Record-Replay tests model. That means that you have to describe all your actions beforehand, anything that would be done to/with mock objects (this is Record phase). Then you have to switch framework into Replay phase and run methods under test. During that calls, framework could throw exceptions in case anything goes wrong (not the way that it was supposed during recording phase). At the end of test you could run special method to verify no expectations were missed. That looked like the following:
[Test]
public void DyamicMockAcceptUnexpectedCall()
{
   //record
   MockRepository mocks = new MockRepository();
   IDemo demo = mocks.DynamicMock<IDemo>();
   //replay
   mocks.ReplayAll();
   demo.VoidNoArgs();
   //verify
   mocks.VerifyAll();
}

Such approach seems good option for integration tests, when you need to test interaction between objects, the calls chain and method arguments. But, if you need to test methods chain, that could signalize that your code is coupled tight and you should consider revising architecture.
In unit testing there is another pattern, called Arrange-Act-Assert. There are 3 sections, first one is for setting variables and environment, second is used for calling code under test and third section contains assertions of variables state after testing. Major difference from Record-Replay is that Assert section contains explicit assertions on what is expected to exist after the test.
Eventually, Rhino Mocks got a support of AAA approach :
[Test]
public void Test()
{
   // arrange
   var dataProvider = MockRepository.GenerateStub<IDataProvider>();
   var processor = new DataProcessor(dataProvider);
   // act
   processor.ProcessData();
   // assert
   dataProvider.AssertWasCalled(x => x.GetData());
}

You do not need to change framework state explicitly, MockRepository instance is not required – so that code is more clean, although API in Rhino Mocks is a real mess now.

mock-objects types


stub


That object has property behavior by defualt – in case the property has a setter – it would persist the data. Read-only properties and methods would only return default values. You can’t check expectations for that object. Instance could be created from interface or class.
var mock = MockRepository.GenerateStub<IRepository>();

mock


The same as stub, but the properties cannot persist data and it is possible to check all expectations for that object at once.
var mock = MockRepository.GenerateMock<IRepository>();

partial mock


That’s also mock, but could be created from class only and it delegates all calls that do not have expectations to its base class (that has been used for creation).
var mock = MockRepository.GeneratePartialMock<ConcreteRepository>();

strict mock


That’s mock, that allows to call only those members that have expectations defined. In case you call method/property without expectation set – exception will be thrown.
var mock = MockRepository.GenerateStrictMock<IRepository>();

Expectations API for mock objects


There is an extension method Expect, that is used for setting expectations. It accepts lambda to defined what method\property is the target.
Expect returns an instance of IMethodOptions – that interface serves for defining the behavior in Fluent style. You could set what to return, what exception to throw, should you ignore arguments of method or invoke callback delegate.
Example:
var mock = MockRepository.GenerateStrictMock<IRepository>();
mock.Expect(m => m.GetData(null, null, null))
     .IgnoreArguments()
     .Return("OK")
     .WhenCalled(mi => Console.WriteLine("method called"));

assertions


VerifyAllExpectations – used to check if all expectations were met. AssertWasCalled and AssertWasNotCalled – explicit checks of certain member of particular class.
mock.VerifyAllExpectations();
mock.AssertWasCalled(m => m.ReadData());
mock.AssertWasNotCalled(m => m.ReadData(null),
   options => options.IgnoreArguments());

There is a lot of possibilities for setting expectations and their validation. Here is simplified example from real development:
[SetUp]
public void CreateMocks()
{
     cacheStub = MockRepository.GenerateStub<ICacheProvider>();
}

[Test]
public void That_Data_Is_Calculated_And_Cached()
{
     string data = "sdgf";
     string key = "some key";
     var dataProviderMock = MockRepository.GenerateStrictMock<IDataProvider>();
     dataProviderMock
         .Expect(y => y.GetData(Arg<string>.Is.Equal(key)))
         .Return(data);
     var calc = new DataCalculator(dataProviderMock, cacheStub);
     calc.Calculate(key);
     dataProviderMock.VerifyAllExpectations();
     cacheStub.AssertWasCalled(y => y.SaveData(
         Arg<string>.Is.Equal(key),
         Arg<string>.Is.Equal(data)));
}

Rhino Mocks is available as a Nuget package from official package source. In general, it is useful for unit testing, possess a lot of options in tuning mocks, but the API brings some confusion into user experience. All those parts of Record-Replay are visible and it is hard to distinguish approaches and decide what to use and what to avoid. It would be good if the code have been cleaned and API have been split appropriately – let’s look at what would happen and if it would be done in future releases (if any Smile)