JAOO - Day 1
Well, what should I tell you. It’s like a dream come true - I’m at the JAOO conference in Aarhus/Denmark.
After some extreme-airport-hopping (4 airports in 7 hours) yesterday and some major problems with the local geography (getting to my hotel), I still managed to survive JAOO Day 1.
On today’s program were some parallel sessions about Ruby on Rails, Spring, Equinox/OSGi and Test Driven Development. I participated in the Equinox and TDD sessions.
The former was held by Tom Watson and Jeff McAffer, two guys from IBM. They first explained the ideas and concepts behind OSGi, followed by a live presentation of a simple “Hello OSGi” bundle (those attendees who had their laptop with them were encouraged to try it themselves). They also provided the source code of a simple chat application, but due to all the (really interesting) discussions, there wasn’t enough time left to try this one in the session (but I started it and - well - it worked).
The bottom line: OSGi is a really interesting technology for glueing your components together, solving all of your classpath issues (well, not quite that is). A minor “problem” is, that development is a little different from “normal” Java development (as with every container there are new things to learn and understand).
Another problem is, that some libraries using a Thread’s context ClassLoader have problems running as OSGi bundle. Unfortunately one of these libraries is Hibernate, which would pose a problem for many people wanting to use OSGi on the server. Luckily there is the concept of a buddy classloader solving this problem, but this is not (yet?) part of the OSGi standard, but only provided by Equinox.
Session 2 - Test Driven Developmen - was moderated by the ThoughtWorker Erik Dörnenburg (I was waiting the whole session to hear the name Martin Fowler, but it just didn’t come). It was a good practical presentation about TDD and what it’s all about (to sum it up: red bar - green bar - refactor, in this order).
The second part of the session was an introduction into jMock. I found out, that I disliked it for a false reason. I always liked it because of its concise syntax (compared to easymock’s record-and-replay mechanism), but I thought that it was somewhat brittle to provide a method’s name as a string (e.g.
mock.expect(once()).method("someMethod")
). This of course poses a problem when you refactor your classes, but the key point is that your test will fail if you provide an invalid method name (jMock checks if a method with the provided name really exists). So you will find out if you did anything wrong.
Well, that’s about all from JAOO Day 1. What’s left is a pleasant feeling in my stomach - the reason may be the most expensive 3 small pieces of roast lamb I have ever had (26 Euro) or the most expensive beer (6,5 Euro for 0,4l … even at the Oktoberfest in Munich you get twice as much). Good night.
October 12th, 2006 at 12:03
“This of course poses a problem when you refactor your classes, but the key point is that your test will fail if you provide an invalid method name (jMock checks if a method with the provided name really exists). So you will find out if you did anything wrong.”
As the author of EasyMock, I also think this is one of the main points, but for another reason: Your tests *pass* first, then you apply a *refactoring*, and then your tests *fail*. So automated refactoring does not work correctly when using jMock mock objects.
Using method calls to define expectations in EasyMock provides more benefits than refactoring safety: Both autocompletion and generation work.
As an example for autocompletion, consider we have a String stored in the variable login, and an object of type User stored in the variable user. Now we like to check that User mock.someMethod(String) is called with the String stored in login, and we like our mock to return the object stored in the variable person.
jMock:
mock.expects(once()).method(”someMethod”).with( eq(login) ).will(returnValue(person));
EasyMock 2:
expect(mock.someMethod(login)).andReturn(person);
With jMock, autocompletion would not work on someMethod, and the autocompletion for login and person would be cluttered with other completions, as the type is not checked.
With EasyMock, autocompletion would work everywhere, and the autocompletion for login and person would not be cluttered with other completions, as the type is checked, i.e. the autocompletion at ’someMethod(’ would only show strings, and the completion at ‘andReturn(’ would only show user objects.
As an example of code generation, let’s say you specify a call to a method which does not exist yet on the mocked interface:
jMock:
mock.expects(once()).method(”notYetExistingMethod”).with( eq(42) );
EasyMock:
mock.notYetExistingMethod(42);
With jMock, you have to run your tests to see that the method is missing, and then to define it by hand in the interface. With EasyMock, modern IDEs generate the method automatically for you.
October 12th, 2006 at 21:31
I am quite aware of the advantages of using pure language constructs (that the compiler can check and the IDE can autocomplete) in contrast to pure strings (that are of course not checked in any way during compile time) - in fact, this is one of the main reasons why we are using EasyMock in a project.
Still, some things are rather hard to get used to.
EasyMock’s record mechanism is really clever: everything is done at language level, no meta-language (Strings) necessary. Unfortunately this implies, that you need this extra replay step before you can really use the mock. I don’t know how many times I forgot to replay my mocks - still, you usually find out when trying to break your test, and it just won’t break because the mock is still in recording mode (or does mock.verify() even throw an exception if the mock has not been replayed?).
The ArgumentMatchers are also a very interesting way to accomplish their tasks (unfortunately hard to understand at first, too). Still jMock’s Constraints are slightlier more compact to use (no additional static method necessary).
So each, EasyMock and jMock, has some things that it can do a little better or easier than the other. In a perfect world we could take the best from both camps and build some kind of JEasyMock (to be pronounced like CheesyMock), but the two concepts are just too different for this to work. Even worse, the two base concepts of the two mock libs are in fact the reason for the shortcomings they have: with EasyMock it just won’t be possible to simply provide an ArgumentMatcher to the mock’s method call (the compiler would complain), and with jMock you’ll never have some more compile time verification. There is just no other way to do these things in their world.
After talking so much about the “problems” of those two mock libs: it’s still great to have fabulous tools like these. I could not imagine testing without something like this.
October 22nd, 2006 at 15:10
Hello Helmut,
The extra replay() step in EasyMock is there by design, not by requirement.
It would be possible to do implement something like expect(mock).aMethod()
meaning the expect gives back an object which allows the definition of expected method calls for te mock. When I implemented EasyMock 2 last year, I opted against it for two reasons. First, it is harder to read, since the parentheses look misplaced. Second, it is not possible to chain responses, like in expect(mock.aMethod()).andReturn(”avalue”) - and this means that type checking for return values would not work. However, this decision may change in a future version of EasyMock.