After years of making half hearted attempts at test driven development I’m finally taking the plunge and doing it properly. After only a few days of doing TDD I got tired of implementing interfaces long hand. It’s especially annoying since you typically only care about one or two methods in the object but have to fill them all out. The trouble comes for the reader of your code who can’t tell immediately what return values you care about and which ones are the default values that were generated for you. So I began looking for mocking framework. My only criteria must work with Java 1.4 – so no annotations or generics. Based on a thread in the JUnit mailing list Mock Framework reviews (https://tech.groups.yahoo.com/group/junit/message/19315) I decided to give JMock and RMock a try.
Why didn’t I try using EasyMock 1.2? Its style just doesn’t appeal to me. Like Vi it is stateful/modal i.e. you have to do things in a particular sequence and you can’t always tell from reading the code what mode your in. In particular there are setup and replay modes. First you build your mock, and then you flip the replay bit. Now calls to the method under test will be verified for conformance. I find this deeply weird. I always hated vi because if you stepped away from your machine and came back you could never quite be sure what mode you were in: command mode or text entry mode. EasyMock suffers the same problem – the replay call can be anywhere (think abstract test cases) – the reader has to guess whether the Mock is ready for use.
This one really appealed to me – a modern mock tool that still supported Java 1.4. In addition it didn’t used strings to find methods it used the methods themselves. Fantastic I thought. On paper this approach appealed to me. Then I tried to write code:
// BTW The example code is dumbed down to avoid introducing other classes and so tests something that is completely pointless. Trust that the code this comes from has a point IRead somethingRead = (IRead) mock(IRead.class); somethingRead.getAttributes(); modify().returnValue(ATTRIBUTES); startVerification(); Attributes attributes = somethingRead.getAttributes(); assertEquals(ATTRIBUTES, attributes);
The first line makes sense, but it’s the second where things get a little weird – we call somethingRead.getAttributes() not to execute but to tell RMock that we wish to change it. In line three we call a Multiplicity modifier to change the return value. Finally we call startVerification() to be allowed to make use of our mock. And there we are back in modal land again. I know some people like Vi but its not me. Just in case I’m out to lunch I tried sharing this code with my team – they all found it hard to wrap their heads around but would use it if I asked nicely. They’re all too young to know what Vi is. One other detail your tests must be derived from RMock’s test case.
N.B. all my remarks are about JMock 1.2 – the last version to support Java 1.4. It’s funny some times how hard you resist something even when it comes with the recommendation of people you respect. Both JB Raingsberger and Bob Martin have remarked that they currently use JMock yet I wasn’t sold. However after finding RMock to confusing for my tastes I thought I better give JMock a try. Here’s the code snippet:
Mock mockRead = mock(IRead.class); IRead somethingRead = (IRead) mockRead.proxy(); mockRead.expects(atMostOnce()).method(“getAttributes”).will(returnValue(ATTRIBUTES)); Attributes attributes = somethingRead.getAttributes(); assertEquals(ATTRIBUTES, attributes);
JMock creates two classes the Mock “manager” – mockRead and the proxy class – somethingRead (i.e. the class under simulation). The readability of the third line is what really appeals to me. I appreciate that mockRead expects that getAttributes will be called at most once and will return the value Attributes. I also like that the mock is always ready for use so there won’t be any issues looking for missing startVerification/verify calls.
- The string based approach to identifying methods will cause us very interesting surprises when the interface items are renamed (this is happens quite a bit because the API’s we’re consuming are still fairly young). N.B. JMock 2.0 appears to address this issue.
- The stock constraints for expects are a bit thin atMostOnce, atLeastOnce, never, once – missing support for don’t care and a specific number of calls. (In my example I don’t care – but I can’t easily communicate that to the reader. RMock definitely had more constraints.
- The language for testing arguments passed to a mock method is a bit limiting so I’m forced to create a custom constraints class to test simply things. In particular to do this: EXPECTED_NAME.equals(((Folder) o).getName()) – I was forced to create a custom class when casting the arg is all I really wanted.
- Can’t mock classes – occasionally I would like to mock something that’s an abstract class. I think that both JMock 2.0 and RMock support this.
Which Mock framework did you choose? Why?
Mark Levison has been helping Scrum teams and organizations with Agile, Scrum and Kanban style approaches since 2001. From certified scrum master training to custom Agile courses, he has helped well over 8,000 individuals, earning him respect and top rated reviews as one of the pioneers within the industry, as well as a raft of certifications from the ScrumAlliance. Mark has been a speaker at various Agile Conferences for more than 20 years, and is a published Scrum author with eBooks as well as articles on InfoQ.com, ScrumAlliance.org an AgileAlliance.org.
I stood in front of the same decision recently and couldn’t find much in form of good comparisons on the net.
I choose EasyMock at the end and am very happy. Especially the addition of the class extensions is great as it allows you to not only mock interfaces but classes as well.
I had the same problem about a year back and found this beaty:
It allowed me to test my code ‘as is’ without defining any mock interfaces (only mock data). It was the one time I ever used aspects and it worked for me 🙂
Check it out!
I am also using EasyMock (the 1.5 enabled version) with great pleasure. Usually I write my tests small enough, so its hard to get confused by the setup, run and verify states (“modes” as you call them) – stateful programming is not a new concept and should be familiar to most whether they like it or not 😉
It sounds like I should give JMock a try again though, I didn’t try it since the 1.4 version and I had the same annoyances like you with the limited set of operations available. (and the string references to methods ofcause, but that was common those days).
To allow a method to be called any number of times (or zero) you can do:
The jMock CGLib extension lets you mock abstract classes.
But yes, jMock 2 is better.
Gwyn Evans says
I’ve tried both JMock and EasyMock but ended up going back to EasyMock (1.2, as I’m also restricted to JDK 1.4 at the moment).
I found that in most tests there was a setup phase, then a point to set the mocks to replay, an invocation of the class under test and then a verification of the mocks. Even where I needed one mock for use in another, the replay needing to be done ‘early’ wasn’t an issue, and on the upsite, I had the advantage of the full IDE support when coding the calls to the mocks.
Note they both let you mock classes, if you need to, and both let you set varying criteria for matching calls, arguments, etc.
LaughingPanda Mocked! Nice & simple.
Thiago D says
Good post. Take a look at this when possible: https://www.aqris.com/display/A/EasyMock+1.2+Wrapper
Ian Robinson says
I haven’t used RMock or EasyMock in anger, but have grown to really like JMock; despite all its faults. It had been adopted already by a project I joined mid-way through, but at that point not really used extensively. Now I hardly write a line of code that isn’t exercised by it.
Admittedly, the string based approach is a real limitation when refactoring.
Just a couple of points to help with your annoyances…
I’m not sure why you would want to set up an expectation for something you don’t care about, but you can specify an exact number of invocations with exactly(expectedCount).
You can mock Classes with JMock using CGLIB.