XpdWiki

FrontPage
RecentChanges
XtC
FindPage
PageIndex
XpApprentices

Set your name in
UserPreferences

Edit this page

Referenced by
XP2003




JSPWiki v2.0.52


MockObjectsCollaborate


a story from Xp2003 by EmilyBache

Charlie Poole was doing a presentation about automated testing to a group of Italien students, when a few of us, including Tim Mackinnon, gatecrashed. We’d heard that Charlie was going to present NUnit and we were interested to take a look at it. Before he got onto that though, he was doing a great job of explaining Test Driven Development clearly and simply in measured, foreigner-freindly English.

Charlie presented a problem. You have a Project, which owns a collection of Configurations, which in turn owns a collection of Assemblies. You want to write unit tests for the Assembly class in isolation – that is, without the tests being dependant on the other classes. One aspect of the functionality you want to test is that when an Assembly object is modified, it should notify its owning Configuration by calling the “setIsDirty” method.

Luckliy, the Assembly class is only dependant on the IConfiguration interface rather than the concrete Configuration class. This makes it easy to write a mock version of the Configuration class which we can use in our test: (note that Charlie wrote his example in C# but I only know Java, so I’ve used that instead.)

 
public class MockConfiguration implements IConfiguration { 
    public boolean dirty = false; 
    public boolean setIsDirty() { 
        this.dirty = true; 
    } 
} 
So the test looks something like this:
 
import junit.framework.TestCase; 

public class AssemblyTest extends TestCase { 

    public void testConfigurationMarkedDirtyWhenModified() { 
        MockConfiguration config = new MockConfiguration(); 
        Assembly assembly = new Assembly(config); 
        assembly.modify(“some new item”); 
        assertEquals(true, config.dirty); 
    } 
} 
I thought this was a well explained, straightforward example showing how to use a Mock Object in order to do isolation testing, but Tim commented that he wouldn’t have written this test using the Mock Object in quite the same way. Tim and two others wrote the paper which first introduced the whole area of Mock Objects when it was published four years ago at XP2000, so we were all interested to hear what he had to say. Charlie asked Tim to climb onto the platform and take the chalk.

What Tim explained was that Mock Objects are not only a means to do isolation testing - they also allow you to specify and verify collaboration between objects. He put it in terms of having a conversation with your pair programming partner along the lines of:

Me - “how would we know if this Assembly object were collaborating correctly with this Configuration object?”

You - “Well, the Configuration object can expect to receive a call to the ‘setIsDirty’ method when we modify something in the Assembly object.”

So that kind of conversation leads us to write a test that looks more like this:

 
import com.mockobjects.dynamic.Mock; 
import junit.framework.TestCase; 

public class AssemblyTest extends TestCase { 

    public void testConfigurationMarkedDirtyWhenModified() {  
        Mock config = new Mock(IConfiguration.class); 
        config.expect(“setIsDirty”); 
        Assembly assembly = new Assembly((IConfiguration)config.proxy()); 
        assembly.modify(“some new item”); 
        config.verify(); 
    } 
} 
There are a number of differences compared with the previous version of the test. For a start, we don’t need to declare a MockConfiguration? class at all, since we use a nice little library, “DynaMock” that dynamically creates mock objects which conform to the interface passed to them – in this case IConfiguration. That is really just for convenience – we could have used the same MockConfiguration? class we declared before, except we would need to add two methods that DynaMock gives us for free – the “expect” and “verify” methods. These methods help you to specify and verify collaboration between the class under test and the mock. In this example, when you call “expect(“setIsDirty”)”, you are saying to the mock “you should expect there to be a call to setIsDirty”, and when you call “verify()” you are saying “check that your expectations were met. If not, raise a failure exception”.

If you look at the two tests, they really achieve the same thing. Both check that the Configuration class is marked dirty when an Assembly is modified, in isolation of the real Configuration implementation. The difference is in the way the test code communicates about object collaboration, and in the conversation you and your programming partner have about the code.

At this point we weren’t sure if we hadn’t lost the Italian students with all this discussion of dynamic Mock factories and assertions of collaboration, and anyway, this was supposed to be Charlie’s talk about NUnit, so Tim gave back the chalk and Charlie carried on. I think we were all impressed with NUnit’s flashy graphics and smooth integration with Visual Studio, but I’m afraid that won’t be my lasting memory of that evening.

I was very pleased that Charlie had asked Tim to contribute to his presentation, because it gave me a whole new insight into the way Mock Objects could be used. I had previously used them much as in Charlie’s first example, to enable isolation testing - but the idea of also using them to specify and verify object collaboration had completely passed me by. It’s funny the way you think you understand something, then someone like Tim can come along and open up a whole new perspective. I think it’s essential that we allow our ideas to be challenged, and that we continue to learn about the techniques we think we know. So, I’m off to download DynaMock(1), and write some tests :-)

(1) available from http://mockobjects.com, or http://nmock.truemesh.com/ for the C# version.


Emily - thanks for the write up, fantastic - I felt as if I was there, which I wish I was. -- PaulS
This dynamic aspect of mocks (and testing, come to that) seems to pass a lot of people by. I recall a conversation in the bar at XP2002 where some folks (who considered themselves XP and unit testing experts) were griping about mocks. I have to think that there was a deal of "not invented here" behind their complaints, but the crucial point that they'd missed was how a mock differs from a stub: in a word, expectations. A mock expects a certain interaction to take place, and complains if if that interaction doesn't happen. Now, this isn't a secret, it's right there in the original paper, and in most of the MO material that's come since. But still a lot of folks, smart ones, too, don't see it.

But once you do see it, the difference made to your tests is astounding. Tests without mocks (or with "passive" mocks), are pretty much executable Hoare triples, which is great! But, unless you're writing in a fully functional language (I can dream), that isn't enough to capture all the design thoughts needed to get to an interface. People tend to talk a lot about the interface on (or of) an object, but an interface is between two (or more) objects. That's why its an interface. With "active" mocks, it's the interface that's being tested, which is a much more powerful idea.

We've just completed a project that included a bunch of tricky server interactions over an unreliable transport, and having a mocked server, one that could say "at this point you should have sent me this, but rather you sent me that", and better yet, was able to say "I have failed in this way", was hugely valuable. --KeithB

The big difference from JUnit assertion that also escapes a lot of people is the idea that the mock fails at the point where its expectations were violated. Not just at the end of the unit test when you're asserting or verifying things.--AdewaleOshineye


In my experience many people use the words 'mock' and 'stub' interchangeably. However, I was interviewed for a position a while back where they
asked me this exact question (the difference between a mock and a stub), which gives one hope I suppose :) --MilesD


Edit this page   More info...   Attach file...
This page last changed on 16-Aug-2004 16:45:41 BST by MilesD.