[image via Brian Schroer]
Because mocking objects is awesome, here is a quick introduction to Rhino Mocks so that we can use it in any C# code.
What is a mock object?
The mock object is a very light weight object where you can simply define what to return when a given method is called with a given parameter. You may at some point want to write a unit test on an object that depends on another class. To avoid this dependecy, you mock out that class and replace it with a mock object. So, for example, if I’m testing an aggregate class:
// combines a list of numbers using a given operator. // e.g. if your operator is addition, and you pass 2,3,4 to the aggregate method, // it will return 2+3+4=9 class Aggregator
{ Aggregator(IOperation op) {...}
double Aggregate( out string text, params double [] numbers) {...}
} // an operator such as addition or subtraction or a random number generator. interface IOperator
{ string DisplayText { get ; set ;}
double Operate( double a, double b);
} |
Mocks give you the freedom from depending on an operator to perform correctly in order to have your unit tests for the aggregator class to pass. Plus sometimes it can be hard to get your operators to behave in strange ways (e.g. return null for some method). The easiest way to unit test this class would be to use a mock object. With a mock object we can easily say that when Operate(3,5) gets called, it should return 17. To do this manually, and for every test would be a lot of work, but this is where rhino mocks comes in. Rhino Mocks, is a .net library that you can use from your C# code to mock out objects.
Setting Up RhinoMocks
In order to set up RhinoMocks to start mocking out your interfaces you’ll have to do a few things. One:
using Rhino.Mocks;
|
Then you’ll have to initialize a mock repository in your setup method. This mock repository is what is used to create the mock objects and to verify that the correct methods got called.
private MockRepository _mocks;
#region Setup/Teardown [SetUp] public void TestInit()
{ _mocks = new MockRepository();
} #endregion |
Creating mock objects
There are a couple options when it comes to creating your mock objects:
- Strict Mock
I used this one most frequently– it creates a mock object where any method calls that you didn’t explicitly expect will cause the test to fail. You can create it this way:IOperator op = _mocks.StrictMock<IOperator>();
Now if I don’t tell the mock object that anything will happen and then I call op.Operate(3,5), the test will fail.
- Dynamic Mock
I’m not entirely sure why you would use this, but if you make an unexpected method call, it will just return the default value for the return type (e.g. null for any object). You can create it this way:IOperator op = _mocks.DynamicMock<IOperator>();
- Partial Mock
This mock object allows you to mock out abstract methods of a class. For example, if Aggregator was an abstract class with an abstract method Operate, we could do the same kind of mocking with a partial mock:Aggregator aggregator = _mocks.DynamicMock<IAggregator>();
Mocking out methods
The bulk of mocking out objects is telling the mock object what calls it should expect. In RhinoMocks you do the following:
Expect.Call(operatorMock.Operate(3,5)).Return(17); |
This tells the mock object that when Operate(3,5) is called, it should return 17. If this method is not called, the test will fail. This is one call only, so if Operate(3,5) is called again, on a strict mock it will fail the test, and on a dynamic mock it will return 0. If you aren’t returning anything (the type of the method is void), you can just leave off the .Return(17). If you have something that you always want to return the same thing, you can use SetupResult.For:
SetupResult.For(operatorMock.Operate(3,5)).Return(17); |
Mocking out Properties
You may think this would be hard, but if you want to mock out a property, you can use Expect.Call and SetupResult.For like you would with a method:
Expect.Call(operatorMock.DisplayText).Return( "+" );
// or SetupResult.For(operatorMock.DisplayText).Return( "+" );
|
You can also use the PropertyBehavior, which means that the property behaves as though it were an auto property
Expect.Call(operatorMock.DisplayText).PropertyBehavior(); |
Ordering
Sometimes you want to make sure that certain things happen in a certain order (by default they can happen in any order). For this you can use the _mocks.Ordered():
using (_mocks.Ordered())
{ Expect.Call(operatorMock.Operate(3,5)).Return(17);
Expect.Call(operatorMock.Operate(17,3)).Return(29);
} |
Now, if Operate(17,3) got called before Operate(3,5), it would fail the test. You can also nest a _mocks.Unordered() inside.
using (mocks.Ordered())
{ Expect.Call(databaseManager.BeginTransaction()).Return(databaseManager);
using (mocks.Unordered())
{
Expect.Call(accountOne.Withdraw(1000));
Expect.Call(accountTwo.Deposit(1000));
}
Expect.Call(databaseManager.Dispose());
} |
In that example, BeginTransaction must happen first, and Dispose must happen last, but the Withdraw and Deposit can happen in either order.
Verification
After you create your mocks, and tell them what you want them to do, you then need to run your actual test, before doing any real code, you’ll have to tell the mock repository that you are ready to start testing:
_mocks.ReplayAll(); |
And then, after you run your code, and do your verifications, you need to verify that the correct methods were called:
_mocks.VerifyAll(); |
Putting it all together
Below is a fictitious example that shows it all together:
[Test] Public void TestMyClass
{ IOperator op = _mocks.StrictMock<IOperator>();
SetupResult.For(operatorMock.DisplayText).Return( "+" );
using (_mocks.Ordered())
{
Expect.Call(operatorMock.Operate(3,5)).Return(17);
Expect.Call(operatorMock.Operate(17,3)).Return(29);
}
_mocks.ReplayAll();
Aggregator aggregator = new Aggregator(op);
String text;
Assert.AreEqual(29, aggregator.Aggregate( out text,3,5,3)
Assert.AreEqual(“3+5=17\n +3=29”,text);
_mocks.VerifyAll();
} |
Related Posts and Links
- The documentation for RhinoMocks is a little bit cryptic, but covers a lot. They also have a pretty good Quick Reference PDF. http://jonkruger.com/blog/2010/03/12/how-to-use-rhino-mocks-documented-through-tests/
- Jon Kruger has a great post that explains RhinoMocks with unit tests
- http://lostechies.com/derickbailey/2010/05/04/rhino-mocks-recursion-and-multiple-return-values-from-stubs/Derick Bailey has a cool method of using a RhinoMocks stub to get multiple return values.