Skip to main content

Recent Comparison of jMock 1.1 and EasyMock 2.2

My Colleges and me are in the process of figureing out wich mock frameworks to use. One of my colleges has experiences with jMock and I have used diffrent versions of easymock. We wanted a detailed comparison to help us decide what the strengths and weaknesses are of the diffrent Mockframeworks. During a web search we discovered this comparison between jMock and Easymock. Although, regarding the authors background not necessarily, but to me most likely, this comparison of Jmock to an unspecified version of Easymock is biased towards jMock.
Many diffrences/disadvantages in this comparison are obsoleted by more recent versions of Easymock, and speculating on the version used in favour of the author would imho result in 1.3 wich dates way back to 2005.

The desription of the link to the jMock project on the easymock project page, states that jMock opposed to easymock uses
another approach to define expectations that results in more flexibility to set expectations (you may specify almost everything imaginable) at the cost of less flexibility when refactoring (refactorings like method renaming and parameter reordering will break the tests) and loss of code completion when defining expectations or test-driving code.
Well this note is definitely true for older version of easymock, and probably stems from the same era as the comparision hosted on the jMock page. Since version 2.0 easymock started to look a lot more like jMock in terms of behaviuor specification. I found that the easymock approach helped me doing test first programming, in cases where I was not only specifying the class under test but also the mocked interfaces, because modern IDEs like eclipse 3.1 and higher may come up with some fancy hinting/auto fixing feature, that will create non existing methods and classes.

Back to the jMock hosted comparison of easymock vs jMock, one drawback the authour of the comparison states is:
EasyMock lets you change the way that arguments are matched on a call-by-call basis, but the syntax is awkward and same matcher applies to all arguments.
Luckily this is not true for Easymock versions higher than 1.3, but let's take closer look anyway.
As example of how (not awkward and brittle) one specifies the beahaviuor in jmock this code fragment send on its mission to insult its readers intelligence:
mock.expects(once()).method("method1").with( eq(a) );
mock.expects(once()).method("method2").with( same(b1), ANYTHING )
.will(returnValue(method2Result));

Did I just read that a mock object(wich really is NOT the mock object) expects an invocation of a local method called once()(wich it does not), and that the result of the expecation is some object that returns probably a method (wich it also doesnt) with something equal to "a"?
Of course I do understand what this behaviour specification is all about, but to be able to write such a specification, one has to learn a syntax/api not as Java-ish as EasyMock, where the only necessary quirk is the distinction between behaviour recording and verification(wich was clear to me at once when I first saw it).

The author continues to state that:
This means that expectations are more verbose but precisely and clearly specify the expected behaviour of the object.By precisely specifying expected behaviour you get flexible tests1 that break only when the actual behaviour is different from expected behaviour, and do not break when you make unrelated changes to application code.
To my knowledge it possible - without extensive API knowledge or awkward syntax - to specify any behaviour with abitrarily varied levels of precision with easymock. In jMock you were spoiled with this kind of flexibility right from the beginning, but this flexibilty is achieved only by introducing some drawbacks i.e.:
  • test development/refactoring is harder because mock-method invocation errors will only show up during runtime
  • after i.e. adding a parameter to method1 one has even more problems fixing this than merely changing the name of method1
The last point is especially dangerous in a multi developer team. The brittleness of the test cases is exactly what I want. There is added value in compile time checks.

Now let's have a look at the Easymock (2.0 and higher) version of the code snippet:
mock.method1(eq(a));
expect(mock.method2(same(b), anyInt())).andReturn(method2result);
Notice the subtile diffrences, in jMock one provides the method parameters in a non typesafe way through the "with" method, while in easymock one provides the arguments matchers where the actual parameters would be written. Also through the use of Java 5 generics in easymock the behaviuor definitions can be checked at compile time for type related mistakes.

Another great diffrence between the two examples are that in the jmock example "mock" is a control object and in the easymock example, "mock" is the mock object, that implements the interface we wich to "mock".

One drawback of easymock is that because method1 returns void we have to call "expectLastCall()" to get an object that allows us to specify some more expectation
like the number of invocations of the last method:

mock.method1(eq(a));
expectLastCall().anyTimes();

expect(mock.method2(same(b), anyInt())).once().andReturn(method2result);

Another more recent comparison dated around march 2006, seems to be done with a newer version of easymock, but it seems that also the author did not (yet) regard/compare more than the absolute minimum mock framework features one might want to use. The key point in favour of easymock were
  • method identification through actual method of the proxy
  • no extension of testcase base class
  • mixing of class mocking and interface mocking is very easy (you just use another implementation of MockControl)
  • very low API complexity
The points in favour of jMock were:
  • No control object is required
  • no replay/verify steps are necessary
Lets shed some more light upon this comparison:
The main point, that no control object is required in jMock is imho false. One exclusively operates on the control object and invokes a getter for the proxy. That is the reason just why
one cannot use the actual methods to specify behaviour. Easymock achieves refactoring safe actual method specification by introducton of its replay/verify concept. Furthermore, by exploiting new Java 1.5 features(static imports, generics, varargs) easymock almost completely frees the user from the burdern of being aware of this dichotomy in his daily work, and it even frees the user from the burden of subclassing some special test case base class as in jMock.

JMock on the other hand allows the user to specify behaviuor without having the recording/playback states, and mock behaviuor is automgically verified by base class methods after the method finishes. Also mock control object can be instantiated by a base class member method.
While this is for sure some helpful syntactic sugar, it is not so hard to do any of this with easymock because of the clever design of the easymock MockControl class and the usage of static imports.


Also the possibility to specify argument matchers was judged as "difficult" in easymock and easy in jMock.

Finally, I would like to point to an interesting article done by Martin Fowler, who explains some interesting aspects of overall applicability of Mock/Stubs/Dummies and Fakes, and tries to open a more general perspective on test doubles of all kinds. He also includes a small comparison of jMock and EasyMock. He also compares jMock to a very outdated version of Easymock it seems, as the code he provides as example, does not make use of the "import static" feature of Java 1.5, as well as some other features that could have been used to make the code alot more like typical jMock code. The article can be found here.
Although this article was updated 02 Jan 07
the easymock example he provides is also based on an obsolete version of easymock. Exactly why the author values mentioning some diffrences between jMOck and easymock is not clear to me. The article focuses on explaining the distinction between stubs and mock, not on comparing mock frameworks.
I will use this opportunity to rewrite this example of easymock:

public class OrderEasyTester extends TestCase {
private static String TALISKER = "Talisker";

private MockControl warehouseControl;
private Warehouse warehouseMock;

public void setUp() {
warehouseControl = MockControl.createControl(Warehouse.class);
warehouseMock = (Warehouse) warehouseControl.getMock();
}

public void testFillingRemovesInventoryIfInStock() {
//setup - data
Order order = new Order(TALISKER, 50);

//setup - expectations
warehouseMock.hasInventory(TALISKER, 50);
warehouseControl.setReturnValue(true);
warehouseMock.remove(TALISKER, 50);
warehouseControl.replay();

//exercise
order.fill(warehouseMock);

//verify
warehouseControl.verify();
assertTrue(order.isFilled());
}

public void testFillingDoesNotRemoveIfNotEnoughInStock() {
Order order = new Order(TALISKER, 51);

warehouseMock.hasInventory(TALISKER, 51);
warehouseControl.setReturnValue(false);
warehouseControl.replay();

order.fill((Warehouse) warehouseMock);

assertFalse(order.isFilled());
warehouseControl.verify();
}
}

Here is the rewrite:
import static org.easymock.EasyMock.*;

public class OrderEasyTester extends TestCase {
private static String TALISKER = "Talisker";

private Warehouse warehouseMock;

public void setUp() {
warehouseMock = createMock(Warehous.class);
}

public void testFillingRemovesInventoryIfInStock() {
//setup - data
Order order = new Order(TALISKER, 50);

//setup - expectations
expect(warehouseMock.hasInventory(TALISKER, 50).andReturn(true);
warehouseMock.remove(TALISKER, 50);
replay(warehouseMock);

//exercise
order.fill(warehouseMock);

//verify
verify(warehouseMock);
assertTrue(order.isFilled());
}

public void testFillingDoesNotRemoveIfNotEnoughInStock() {
Order order = new Order(TALISKER, 51);

warehouseMock.hasInventory(TALISKER, 51).andReturn(false);
replay(warehouseMock);

order.fill((Warehouse) warehouseMock);

assertFalse(order.isFilled());
verify(warehouseMock);
}
}



to be continued...

Comments

Popular posts from this blog

Lazy Evaluation(there be dragons and basement cats)

Lazy Evaluation and "undefined" I am on the road to being a haskell programmer, and it still is a long way to go. Yesterday I had some nice guys from #haskell explain to me lazy evaluation. Take a look at this code: Prelude> let x = undefined in "hello world" "hello world" Prelude> Because of Haskells lazyness, x will not be evaluated because it is not used, hence undefined will not be evaluated and no exception will occur. The evaluation of "undefined" will result in a runtime exception: Prelude> undefined *** Exception: Prelude.undefined Prelude> Strictness Strictness means that the result of a function is undefined, if one of the arguments, the function is applied to, is undefined. Classical programming languages are strict. The following example in Java will demonstrate this. When the programm is run, it will throw a RuntimeException, although the variable "evilX" is never actually used, strictness requires that all argu

Learning Haskell, functional music

As you might have realized, I started to learn Haskell. One of the most fun things to do in any programming language is creating some kind of audible side effects with a program. Already back in the days when I started programming, I always played around with audio when toying around with a new language. I have found a wonderful set of lecture slides about haskell and multimedia programming, called school of expression. Inspired by the slides about functional music I implemented a little song. Ahh ... and yes it is intended to sound slightly strange . I used the synthesis toolkit to transform the music to real noise, simply by piping skini message to std-out. I used this command line to achieve the results audible in the table: sven@hhi1214a:~/Mukke$ ghc -o test1 test1.hs && ./test1 | stk-demo Plucked -n 16 -or -ip Sound samples: Plucked play Clarinet play Whistle(attention very crazy!) play As always the source... stueck = anfang :+: mitte :+: ende anfang = groovy :+: (Trans

The purpose of the MOCK

In response to a much nicer blog entry, that can be found here . There are actually several distinct "tests" that make up usual unit tests, among them two that really do stand out: one kind of testing to test method flows, one to test some sort of computation. Mock objects are for the purpose of testing method flows. A method flow is a series of message transmissions to dependent objects. The control flow logic inside the method(the ifs and whiles) will alter the flow in repsonse to the parameters of the method call parameters passed by calling the method under test, depending on the state of the object that contains the method under test and the return values of the external method calls(aka responses to the messages sent). There should be one test method for every branch of an if statement, and usuale some sort of mock control objects in the mock framework will handle loop checking. BTW: I partly use message transmission instead of method invocation to include other kind