Whenever I have a problem that can be solved with some sort of framework I ask a colleague for advice on the best framework to use. The answer I get is always a strong opinion in favour of a particular framework, say framework 'X'
“'X' is the best option by far the colleague will say.”
and usually once you start using it another colleague will come along and tell you that 'X' is completely wrong and that you would have been much better off using 'Y'
“Yes 'Y' is the best thing to use, you should have used that and then you would not be having the problems you are having. The second person will say.”
This is particularly annoying as the statement is correct, there would not be the problems if you swapped one framework for another - it would be an entirely different set of problems.
I digress...
I recently needed to start using a mocking framework for unit tests (Now that I am no longer using Groovy and Grails which has good support of its own). My choices boiled down to JMock or Easymock. Initially I thought I would use whatever was already being used within the department but I found that both were in use, so I was left with the option of taking the advice of colleagues...
This time, however, I did not get the answer I expected instead I got something else – indifference. I got answers like 'There both OK, use which you like' and 'I prefer JMock but I think Easymock has got a lot better recently'.
So not having any strong advice (be it good or bad) I just picked Easymock at random and got on with learning it. Having been using it for a few weeks I have found it very good.
My one criticism is that the base framework is only designed to work with interfaces. While I believe that programming to interfaces is a good idea I don't think that having an interface to match every single class you create is really necessary. Obviously I am not alone in this opinion as there is an easymock extension package which works with concrete classes and its great. It works in exactly the same way as the base package does for interfaces but you can create mocks from classes.
Both packages use the same API, just with different packages structures. An EasyMock class can be found in the package org.easymock and is used for interfaces only, while an identical EasyMock class can be found in org.easymock.classextension and is used for classes.
It is highly likely that both classes will be needed in any tests written where there is a mixture of classes and interfaces to mock out. The clash in class name then becomes an issue. You have to import one set of classes and reference the other with its fully qualified name:
This does not work:
1 interface MyInterface {}
2 class MyClass {}
3
4 // some test
5 import org.easymock.EasyMock;
6
7 public void setUp() {
8 MyInterface mockMyInterface = EasyMock.createMock(MyInterface.class); // works
9 MyClass mockMyClass = EasyMock.createMock(MyClass.class); // fails MyClass is not an interface
10 }
So you have to do this:
1 interface MyInterface {}
2 class MyClass {}
3
4 // some test
5 import org.easymock.EasyMock;
6
7 public void setUp() {
8 MyInterface mockMyInterface = EasyMock.createMock(MyInterface.class); // works
9 MyClass mockMyClass = org.easymock.classextension.EasyMock.createMock(MyClass.class); // works – correct class used
10 }
This looks simple but you end up with more than just a createMock state for each mock. You have expect/replay/verify statements as well and quickly the tests become a bit combersome.
Java 5 and later provides a simple option in the form of static imports. Thus you can statically import one set of classes and access the methods directly and import the other in the normal way:
1 interface MyInterface {}
2 class MyClass {}
3
4 // some test
5 import static org.easymock.classextension.EasyMock.*;
6 import org.easymock.EasyMock;
7
8 public void setUp() {
9 MyInterface mockMyInterface = EasyMock.createMock(MyInterface.class); // works
10 MyClass mockMyClass = createMock(MyClass.class); // works – method statically imported.
11 }
Slightly easier but still a bit of a problem.
Cue all the comments from people telling me I should have used JMock.
syntax highlighted by Code2HTML, v. 0.9.1