At a recent developer group meeting I was asked why we were using Rhino Mocks instead of NMock. He also pointed out that NMock had minor api rewrite that made it nicer to use.
My answer was that Rhino Mocks was standardized before I started with my current team, but I would look into NMock. It never hurts to comparison shop.
So to get get started. If you are not familiar with either framework, I suggest looking at their quick start guides:
Rhino Mocks Quick Start
NMock Quick Start
How to mock an object.
NMock: |
Mockery mocks = new Mockery(); |
Rhino Mocks |
MockRepository mocks = new MockRepository (); |
So far so good, no real difference between them. Rhino Mocks has a minor more typing involved, but frankly, I have code templates for all of that anyway.
Which is better: Tie. They both work just fine.
But lets backup a second. What does IMyInterface look like. This is what we are going to work with:
public interface IMyInterface
{int MyProperty { get; set; }
int Add(int i, int j);void MyMethod(int i, int j);event EventHandler<EventArgs> MyEvent;
}
Mock libraries create fake objects to send to your real objects. Your real object can call the fake object's methods and properties, but you have to give the Mocked objects their values (this is called setting expectations). First to note: you aren't testing the mocked object, you are testing the object calling the mocked object.
Anyway, if you need more info on where or when to use a mocked object I'm sure Google will have many excellent examples for you.
OK, so now that we have that part set, lets move on.
Set and get a property:
Quick note: this is telling the mocked object to expect the property to be set to a value. We are not actually setting the value. Also, when we get the property, we have to tell the mock library what to return.
NMock |
// set the property |
RhinoMock |
// set the property |
OK, both sets of calls are supposed to be equivalent. The first thing to notice is that whatever typing saving we had in the construction of the mock object has not been completely lost. But I still think amount of typing it takes to do something is somewhat shallow, so lets dig deeper into the syntax.
As you can see, in NMock nothing is implied. The properties setter will be called exactly once, and the value will be retrieved exactly once. In Rhino Mocks, that detail is implied. But more troubling with NMock is the reliance on using strings to specify which property is being called. Where as with Rhino Mocks, you are using the mocked interface itself.
So if I change the name of my property on the interface, both tests will fail. But with Rhino Mocks it will fail at build time, NMock will have to wait for run time. Also, if I'm using Find Usages (a feature of ReSharper) to find every place that MyProperty is being used, it will pick up the Rhino Mocks code, but will not pick up the NMock code. To me that is a usability issue.
Rhino Mocks wins.
Next test: Call a function and return a value; call a method
NMock |
Expect.Once.On(aMock).Method("Add").With(1,2).Will(Return.Value(3)); |
Rhino Mock |
Expect.Call(aMock.Add(1,2)).Return(3); |
The nice thing here is that both libraries are consistent in their approach. I still don't like how you have to specify the method names by a string though. Also, the Will(Return.Value()) does not seem natural to me.
But I do have to nock Rhino Mocks on how it does methods a bit. If there is nothing to return, you just call the method. If there is something to return you use the Expect.Call method. This does not seem as consistent as it should.
Rhino Mocks wins.
Handle multiple calls
This is actually kind of interesting. With the NMock api, specifying multiple calls is actually quite natural, where as Rhino mocks seems like a hack. In NMock the Expect function has the following options:
- Exactly(int count)
- AtLeastOnce
- AtLeast(int count)
- AtMost(int count)
- Between(int start, int stop)
- Never
With Rhino mocks there are two ways to do this, but in both cases you use the Repeat object. Remember if you are calling something that doesn't return a value, you don't have to use the Expect object. So Rhino Mocks adds the LastCall method. LastCall modifies the expectations for the last call you made to a mocked object.
But you are using the Repeat object itself. And here is what you get with that:
- Any()
- AtLeastOnce()
- Once()
- Twice()
- Times(int count);
- Time(int min, int max)
- Never()
First thing I will note between Rhino Mocks Repeat and NMocks Expect is that they are mostly equivalent. I would like the wording of NMocks Between over the Rhino Mocks Times function though. But, Rhino Mocks is missing the AtLeast(int count) function.
So if I wanted to call both methods of my interface at least 2 times, here is what it would look like.
NMock |
Expect.AtLeast(2).On(aMock).Method("Add").With(1,2).Will(Return.Value(3)); |
Rhino Mocks |
Expect.Call(aMock.Add(1,2).Return(3).Repeat.Times(2, int.Max); |
As much as I love Rhino Mocks, NMock is the winner on the repeating calls front. The syntax makes more sense and is easier to follow than Rhino Mocks. But to fix Rhino Mocks should be hard. Add an AtLeast function and make it possible to use the Expect function on methods with no return values and I think it is there.
But I still don't completely like NMock as either. I don't like it that you have to set the number of times something is being called before you tell the mock library WHAT is being called. I don't thing that helps readability at all.
Winner: NMock.
Raising Events
All of us have this. Small little routines that are only used when an event is raised. So we need a way to mock the event so we can test that code.
NMock |
// First read this article: http://becomingagile.blogspot.com/2007/03/raising-events-in-nmock-20.html |
Rhino Mocks |
aMock.MyEvent += null; |
Can you raise events in NMock: Yes. Is it directly supported: No.
Can you raise events in Rhino Mock: Yes. Is it directly supported: Yes.
Now working with events can be a bit hard. Working with events on a fake object takes a bit of mental yoga to really make sure you understand what is going on as well. I am not overly ecstatic with how Rhino Mocks does events...but it is supported without doing Google searches and writing another class.
Rhino Mocks wins.
Throwing Exceptions
We also have code that catches exceptions. How often do you test that code? You should. Here is how you do it.
NMock |
Expect.Once.On(aMock).Method("MyMethod").With(1,2) |
Rhino Mocks |
Expect.Call(aMock.MyMethod(1,2)).Throw(new Exception("Hi there"); |
So again, both do the job. But I still like the Rhino Mocks terseness better.
Rhino Mocks wins.
Summary
In the end I will stick with Rhino Mocks. The Method(string methodName) style still just kills it for me because it breaks compile-time checking, and the fact that you can't set method parameters in a type safe way. If I change a something in an interface I want that to break my build -- even in my test code!
Will NMock do the job: yes. But I still think Rhino Mocks does it better.