Manual Mocking - Resisting the Invasion of Dots and Parenthesis

Manual Mocking: Resisting the Invasion of Dots and Parentheses

Posted by Uncle Bob on Wednesday, October 28, 2009

The twittersphere has been all abuzz today because of something I tweeted early this morning (follow @unclebobmartin). In my tweet I said that I hand-roll most of my own mock objects in Java, rather than using a mocking framework like mockito.

The replies were numerous and vociferous. Dave Astels poignantly stated that hand-rolling mocks is so 2001!

So why do I roll my own mocks?

Consider the following two tests:

public class SelectorTest {   private List<Object> list;    @Before   public void setup() {     list = new ArrayList<Object>();     list.add(new Object());   }    @Test   public void falseMatcherShouldSelectNoElements_mockist() {     Matcher<Object> falseMatcher = mock(Matcher.class);     Selector<Object> selector = new Selector<Object>(falseMatcher);     when(falseMatcher.match(anyObject())).thenReturn(false);     List<Object> selection = selector.select(list);     assertThat(selection.size(), equalTo(0));   }    @Test   public void falseMatcherShouldSelectNoElements_classic() {     Matcher<Object> falseMatcher = new FalseMatcher();     Selector<Object> selector = new Selector<Object>(falseMatcher);     List<Object> selection = selector.select(list);     assertThat(selection.size(), equalTo(0));}    private static class FalseMatcher implements Matcher<Object> {     public boolean match(Object element) {       return false;     }   } }

The first test shows the really cool power of mockito (which is my current favorite in the menagerie of java mocking frameworks). Just in case you can’t parse the syntax, let me describe it for you:

The second test needs no explanation.

...

And that’s kind of the point. Why would I include a bizzare, dot-ridden, parentheses-laden syntax into my tests, when I can just as easily hand-roll the stub in pure and simple java? How hard was it to hand-roll that stub? Frankly, it took a lot less time and effort to hand-roll it than it took to write the (when(myobj.mymethod(anyx())).)()).))); statement.

OK, I’m poking a little fun here. But it’s true. My IDE (InteliJ) generated the stub for me. I simply started with:

Matcher<Object> falseMatcher = new Matcher<Object>() {};

InteliJ complained that some methods weren’t implemented and offered to implement them for me. I told it to go ahead. It wrote the ‘match’ method exactly as you see it. Then I chose “Convert Anonymous to Inner…” from the refactoring menu and named the new class FalseMatcher. Voila! No muss, no fuss, no parenthetic maze of dots.

Now look, I’m not saying you shouldn’t use mockito, or any of these other mocking tools. I use them myself when I must. Here, for example, is a test I wrote in FitNesse. I was forced to use a mocking framework because I did not have the source code of the classes I was mocking.

 @Before   public void setUp() {     manager = mock(GSSManager.class);     properties = new Properties();   }    @Test   public void credentialsShouldBeNonNullIfServiceNamePresent() throws Exception {     properties.setProperty("NegotiateAuthenticator.serviceName", "service");     properties.setProperty("NegotiateAuthenticator.serviceNameType", "1.1");     properties.setProperty("NegotiateAuthenticator.mechanism", "1.2");     GSSName gssName = mock(GSSName.class);     GSSCredential gssCredential = mock(GSSCredential.class);     when(manager.createName(anyString(), (Oid) anyObject(), (Oid) anyObject())).thenReturn(gssName);     when(manager.createCredential((GSSName) anyObject(), anyInt(), (Oid) anyObject(), anyInt())).thenReturn(gssCredential);     NegotiateAuthenticator authenticator = new NegotiateAuthenticator(manager, properties);     Oid serviceNameType = authenticator.getServiceNameType();     Oid mechanism = authenticator.getMechanism();     verify(manager).createName("service", serviceNameType, mechanism);     assertEquals("1.1", serviceNameType.toString());     assertEquals("1.2", mechanism.toString());     verify(manager).createCredential(gssName, GSSCredential.INDEFINITE_LIFETIME, mechanism, GSSCredential.ACCEPT_ONLY);     assertEquals(gssCredential, authenticator.getServerCredentials());   }

If I’d had the source code of the GSS classes, I could have created some very simple stubs and spies that would have allowed me to make these tests a lotcleaner than they currently appear. Indeed, I might have been able to test the truebehavior of the classes rather than simply testing that I was calling them appropriately…

Mockism

That last bit is pretty important. Some time ago Martin Fowler wrote a blog about the Mockist and Classical style of TDD. In short, Mockists don’t test the behavior of the system so much as they test that their classes “dance” well with other classes. That is, they mock/stub out all the other classes that the class under test uses, and then make sure that all the right functions are called in all the right orders with all the right arguments. etc. There is value to doing this in many cases. However you can get pretty badly carried away with the approach.

The classical approach is to test for desired behavior, and trust that if the test passes, then the class being tested must be dancing well with its partners.

Personally, I don’t belong to either camp. I sometimes test the choreography, and I sometimes test the behavior. I test the choreography when I am trying to isolate one part of the system from another. I test for the behavior when such isolation is not important to me.

The point of all this is that I have observed that a heavy dependence on mocking frameworks tends to tempt you towards testing the dance when you should be testing behavior. Tools can drive the way we think. So remember, you dominate the tool; don’t let the tool dominate you!

But aren’t hand-rolled mocks fragile?

Yes, they can be. If you are mocking a class or interface that it very volatile (i.e. you are adding new methods, or modifying method signatures a lot) then you’ll have to go back and maintain all your hand-rolled mocks every time you make such a change. On the other hand, if you use a mocking framework, the framework will take care of that for you unless one of the methods you are specifically testing is modified.

But here’s the thing. Interfaces should not usually be volatile. They should not continue to grow and grow, and the methods should not change much. OK, I realize that’s wishful thinking. But, yes, I wish for the kind of a design in which interfaces are the least volatile source files that you have. That’s kind of the point of interfaces after all… You create interfaces so that you can separate volatile implementations from non-volatile clients. (Or at least that’s one reason.)

So if you are tempted to use a mocking framework because you don’t want to maintain your volatile interfaces, perhaps you should be asking yourself the more pertinent question about why your interfaces are so volatile.

Still, if you’ve got volatile interfaces, and there’s just no way around it, then a mocking framework may be the right choice for you.

So here’s the bottom line.

Am I telling you to avoid using mocking frameworks? No, not at all. I’m just telling you that you should drive tools, tools should not drive you.

If you have a situation where a mocking tool is the right choice, by all means use it. But don’t use it because you think it’s “agile”, or because you think it’s “right” or because you somehow think you are supposed to. And remember, hand-rolling often results in simpler tests without the litter of dots and parentheses!

Comments