I'm a sucker for horror stories (and there's that other little matter of being biased towards state-based tests.) As with most things, there is more than one way to use a tool - mock frameworks are no exception. The folks at mockobjects.com have a new book out which explains the right way (not read it yet; maybe I'll still be converted into a mockist.)
Personally my pet-peeve with mock frameworks has been the learning curve. Usually you don't have a dedicated time-slot to learn a mock framework (and that's kind of a good constraint since the mock frameworks are flexible, powerful and consequently huge); I'd bet that most of us learn them while trying to get a test to pass. Nothing like a reluctant mock framework with cryptic error messages between you and a green bar, to get you into real-curse-practice. The only thing that comes a distant second is "Which is better? Rhino Mocks or Moq ?" from people who haven't explored either of them. If both of them scratch your itch, take a pick!
So I've tried to list down the most probable scenarios and try each of them with RhinoMocks, Moq and jMock (always wanted to write some tests in jUnit).
- Expect a Call on mockCollaborator.method()
- Expect a call on mockCollaborator.getProperty and return something
- Expect n calls to mockCollaborator.Method()
- Return values from mockCollaborator.Method()
- Expect no call (Don't call me!)
- Throw an exception in response to an expected call on mockCollaborator.Method()
- Custom callbacks or blocks of code to execute when a mockCollaborator.Method() is called
- Raise an event from a mock collaborator
- Argument Constraints
- Expect a sequence of calls in a specific order
A template for interaction-tests
For state-based tests, I'd usually write my assert first, step back to the action that will lead to the assert and finally arranging everything for the test to work. However this doesn't exactly work for interaction-based tests: In this realm, it's more helpful to write the action first, then the expectations and other steps for arrange and finally assert (which sometimes is just verifying that the expected mocks were called. Some frameworks like jMock do it automatically at the end of the test.)
Arrange
- create mock objects for collaborators that you want to mock( not Stub. I hope you've read Martin Fowler's paper [link] on the difference.)
- Create your test subject (here a Bakery type) and inject the mock collaborators via ctor/setter methods.
- Define the interaction via 'expects'. e.g. I expect the test subject to call methodX on collaboratorA with these parameters.
- State the action/behavior that is the primary focus of this test
- Assert any state-change (if applicable)
- Verify all expected calls on the collaborators were called.
Source Code:
The source code for this series is available for browse/checkout (you'll need subversion to checkout) at
Dot Net code
Java code
#1: Expect a Call on mockCollaborator.method()
- Rhino v3.5 (with NUnit 2.4.8)
Let's see how we do this in Rhino Mocks 3.5 - use the above section to work through this example.
Rhino mocks has changed with a (IMHO noob-friendly/simpler) syntax with version 3.5 - Prior to that an explicit record-replay style was the norm. So if you're using a prior version, try moving to v3.5. (There is a forsaken commented-out source file in the above mentioned link for old-skool Rhino).
To declare that you expect a method to be called, you use the Expect method on the respective mock object. Lambda expressions, Generics and type-inference result in compile-time checks and Intellisense guiding you all the way.
The below expectation reads "On the mockChef, expect Bake to be called with Vanilla and false as arguments." (when someone calls PlaceOrder() on the bakery, which employs the Chef)
I'm not going to post the code to make this pass inline (for honoring the memory of brevity in blog posts). I suggest you try TDDing your way through like me / refer to the source repository.
[Test]
public void Test_ExpectMethodCall()
{ // arrange : create mocks
var mockChef = MockRepository.GenerateMock<Chef>();
// arrange: inject dependencies
Bakery bakery = new Bakery(mockChef);
// arrange: expect the Bake method on Chef to be called
mockChef.Expect(chef => chef.Bake(CakeFlavors.Vanilla, false));
//act
bakery.PlaceOrder(new Order { Flavor = CakeFlavors.Vanilla, WithIcing = false, Quantity = 1 });
//assert
mockChef.VerifyAllExpectations();
}
- Moq v 2.0.5 (with NUnit 2.4.8)
[Test]
public void Test_ExpectMethodCall()
{
//arrange
var mockChef = new Mock<Chef>();
//arrange: inject dep
var bakery = new Bakery(mockChef.Object);
// arrange: expect
_mockChef.Setup(chef => chef.Bake(CakeFlavors.Vanilla, true));
//act
_bakery.PlaceOrder(new Order { Flavor = CakeFlavors.Vanilla, WithIcing = true, Quantity = 1 });
//assert
_mockChef.VerifyAll();
}
Differences
#1: mockChef.Object is the mock collaborator; this is a common stumble for people new to Moq. I think (unverified) this is due to Moq's design of not having a different Repository or Mockery type.
#2: Moq uses Setup for expecations (instead of Rhino's Expect)
- jMock 2.5.1 (with jUnit 4.8.1)
jMock is the Java mock framework distilled from the experience of the gurus at mockobjects.com ; they have a new book out and are the recognized pioneers of the "Mock objects" technique. I highly recommend their second revision of the acclaimed 'Mock Roles not objects' paper.
So let's see how the test looks like in jMock:
Mockery context = new JUnit4Mockery();
@Test
public void test_expectCall()
{
Chef mockChef = context.mock(Chef.class);
Bakery bakery = new Bakery(mockChef);
context.checking( new Expectations() { {
oneOf(mockChef).bake(CakeFlavors.Pineapple, false );
} } );
bakery.placeOrder( new Order(CakeFlavors.Pineapple, false, 1) );
// mockChef.Verify() - autoverified : framework :)
}
Differences
#1: jMock has a more fluent approach to specifying expectations - look inside the Expectations creation. It reads 'Expect one invocation on mockChef of method bake with parameters Pineapple and false. Refer to the nicely written jMock cheatsheet in case you're feeling a bit lost.
#2: You don't need to explicitly verify expectations - automatically done at the end of a test case.
#2 Expect a call on mockCollaborator.getProperty and return something
I've factored out common code into a SetUp method to shorten the code snippets. In general, .Net properties = one get_property method + one set_property method + one backing field. Syntactic sugar!
So when someone queries Bakery.IsOpen, check to see if the Chef is available.
- Rhino Mocks
[Test]
public void Test_ExpectPropertyGet()
{
_mockChef.Expect(chef => chef.IsAvailable).Return(true);
Assert.IsTrue(_bakery.IsOpen);
_mockChef.Expect(chef => chef.IsAvailable).Return(false);
Assert.IsFalse(_bakery.IsOpen);
_mockChef.VerifyAllExpectations();
}
Note the new Return method tagging along with the Expect to signify what should be returned when the Bakery makes a call to Chef#IsAvailable
- Moq
[Test]
public void Test_ExpectPropertyGet()
{
_mockChef.Setup(chef => chef.IsAvailable).Returns(true);
Assert.IsTrue(_bakery.IsOpen);
_mockChef.Setup(chef => chef.IsAvailable).Returns(false);
Assert.IsFalse(_bakery.IsOpen);
_mockChef.VerifyAll();
}
Moq calls it Returns which IMHO reads better.
- jMock
Java does not have properties as first class language features. They are manually implemented as accessor/mutator method pair and a backing field.
#3: Expect n calls to mockCollaborator.Method()
So if I place an Order for 3 Pineapple cakes, I'd expect the Chef#Bake to be called thrice.
- Rhino Mocks
[Test]
public void Test_ExpectMultipleCalls()
{
_mockChef.Expect(chef => chef.Bake(CakeFlavors.Pineapple, true)).Repeat.Times(3);
_bakery.PlaceOrder(new Order { Flavor = CakeFlavors.Pineapple, WithIcing = true, Quantity = 3 });
_mockChef.VerifyAllExpectations();
}
Tag on the Repeat property to the Expect if you expect it to be called n times.
Caveat: the test fails if the mock isn't called at least 3 times. If you call it 3 or more times, the test passes. So if you have a need for exactly thrice, dive into the rhino mocks docs and let me know if you figure out a way to make it work.
- Moq
[Test]
public void Test_ExpectMultipleMethodCalls()
{
_bakery.PlaceOrder(new Order { Flavor = CakeFlavors.Pineapple, WithIcing = false, Quantity = 3 });
_mockChef.Verify( chef => chef.Bake(CakeFlavors.Pineapple, false), Times.Exactly(3), "Chef should have been called thrice!");
}
Differences:
#1. With Moq, you specify this during verification with an overload of Verify (as opposed to while defining expectations)
#2 This test will pass only if Bake is called Exactly thrice (unlike Rhino)
- jMock
@Test
public void test_expectMultipleCalls()
{
context.checking( new Expectations() {{
exactly(3).of(_mockChef).bake(CakeFlavors.Pineapple, false);
}} );
_bakery.placeOrder( new Order(CakeFlavors.Pineapple, false, 3) );
}
jMock wins this one for readabililty.
#4: Return values from mockCollaborator.Method()
Refer to #2 for Rhino and Moq. You tag on a Return/Returns method call to the expectation.
Let's say the bakery being a charitable organization, responds to a PleaseDonate message at the end of the day from cake-loving orphans. The bakery will ask the Chef to bake one for them after checking to see if they have surplus stocks in inventory.
- jMock
@Test
public void test_expectCallAndReturnValue()
{
context.checking( new Expectations() {{
oneOf(_mockInventory).isEmpty();
will(returnValue(false));
oneOf(_mockChef).bake(CakeFlavors.Pineapple, false);
}} );
_bakery.pleaseDonate( OrderForOnePineappleCakeNoIcing() );
}
jMock has a will method to signify what will happen when the method is invoked. Use the indentation (convention) so that it reads better.
#5:Expect no call (Don't call me!)
When the orphans send a PleaseDonate() and there are no surplus stocks in inventory, you wouldn't want to bother the overworked chef at the end of a weary day.
- Rhino Mocks
[Test]
public void Test_ExpectNoCall()
{
_mockInventory.Expect(inv => inv.IsEmpty).Return(true);
_mockChef.Expect(chef => chef.Bake(Arg<CakeFlavors>.Is.Anything, Arg<bool>.Is.Anything))
.Repeat.Never();
_bakery.PleaseDonate(OrderForOnePineappleCakeNoIcing);
_mockInventory.VerifyAllExpectations();
_mockChef.VerifyAllExpectations();
}
Note: This snippet gives you a sneak peek of Argument Constraints. In short the second line states 'mockChef#Bake should not be called (irrespective of arguments)' Bring the .Repeat.Never() clause into plain view by placing it on a new line with one level of indentation.
- Moq
[Test]
public void Test_ExpectNoCall()
{
_mockInventory.Setup(inventory => inventory.IsEmpty).Returns(true);
_bakery.PleaseDonate(OrderForOnePineappleCakeNoIcing);
_mockChef.Verify(chef => chef.Bake(It.IsAny<CakeFlavors>(), It.IsAny<bool>()), Times.Never());
_mockInventory.VerifyAll();
}
Differences:
#1 Moq takes a different path of leaving the invocation-count check till the very end. Use the Verify Overload with Times.Never() as in Section#3
#2 Argument constaints in Moq read slightly better than Rhino.
- jMock
@Test
public void test_expectNoCall()
{
context.checking( new Expectations() {{
oneOf(_mockInventory).isEmpty();
will(returnValue(true));
never(_mockChef).bake( CakeFlavors.Pineapple, false );
}});
_bakery.pleaseDonate( OrderForOnePineappleCakeNoIcing() );
}
jMock doesn't hide intent with never() leading the expectation. jMock's API shows the thought that's been put into it.
5 down. 5 for the next part.
I have recently been looking at Moq, I am a long time user of the Rhino AAA syntax.
ReplyDeleteThe key issue I have with Moq is as follows. Try and set up a mock object where a call to function X with one set of params returns value 1 and call to function X with different params returns value 2.
Everything falls apart and you are into ugly pattern matching and work arounds to solve. The trouble is this is a common thing to require as sooner or later you are looping over data calling operations.
Have I missed something or does Moq not handle this clean like Rhino does.
Rhino
mockObj.Expect(x => x.DoWork("a", obj1, 2)).Return(true);
mockObj.Expect(x => x.DoWork("a", obj2, 2)).Return(false);
try this in Moq (replacing Expect with Setup and both calls return false
This should work out-of-the-box. I suspect obj1 and obj2 - are they custom types? If they are Equal (i.e. obj1.Equals(obj2) returns true, then you have effectively overwritten the first expectation. Hence both calls will return false.
DeleteHere's a passing test to prove that it does - Moq v3.1.416.3 (quite old I think)
[Test]
public void MoqDefense()
{
var mock = new Mock();
mock.Setup(m => m.Do("a")).Returns(true);
mock.Setup(m => m.Do("z")).Returns(false);
Assert.IsTrue(mock.Object.Do("a"));
Assert.IsFalse(mock.Object.Do("z"));
}
See, I would consider that to be a bad unit test. If you are setting up another value, it should be in a different test; your test does not seem granular enough.
Delete