Dirt Simple Mock Objects In Groovy
Posted on May 30, 2007 by Scott Leberknight
I've just started on a new project and of course we want to ensure all, and I really mean all, our code is tested. Now, this being a Java project many people assume 80% is pretty good and that getting upwards of 90% coverage and beyond takes a superhuman effort. In the past I would have agreed. Now that I am learning Groovy, however, I no longer agree and now think it is not only possible to get above 90% coverage and close to 100%, but quite easy.
First some background on why normally 80% is acceptable. Well, it is simply that Java is not very flexible when it comes to mocking certain types of objects. For example, try mocking a standard JDK class that is marked as final
and making it do your bidding. Not easy. It is easy to mock classes that implement an interface and even non-final classes using things like jMock and EasyMock.
Let's take an example. We have some reflective code that uses the java.lang.reflect.Field
class' get() method. This method throws IllegalArgumentException
and IllegalAccessException
, the latter of which is a checked exception. Since there is nothing meaningful we can really do about a IllegalAccessException
we catch it and rethrow as an IllegalStateException
, which is a runtime (unchecked) exception. The problem is that covering the case when an IllegalAccessException
is thrown is not something you can mock using a tool like EasyMock, even the cool EasyMock Class Extension, since the class is marked final
.
Last week I found something called jmockit which is very cool and essentially uses some Java 5 class instrumentation magic (you must specify a javaagent
to the JVM when running your tests) to replace byte code at runtime. This allows you to literally mock anything at all, except for the minor issue that if you want to mock methods in a JDK class like Field
all the test classes must be loaded by the boot class loader, which means you have to use the -Xbootclasspath
startup option. This starts to really become intrusive, complicate your build process, and generally make things a lot more complex. Even needing to run the JVM with -javaagent:jmockit.jar
is intrusive and somewhat complicated.
Enter Groovy. I am a total beginner at Groovy having only attended some sessions at various conferences like No Fluff Just Stuff and JavaOne, a little tinkering with the Groovy shell, and having purchased Groovy in Action. Within an hour or so of tinkering I was able to produce an IllegalAccessException
from a mocked Field
using Groovy. The following code is probably crap (again being a Groovy newbie) but is ridiculously simple and readable nonetheless:
import groovy.mock.interceptor.MockFor import java.lang.reflect.Field class SimpleUnitTest extends GroovyTestCase { void testMockingField() { def fieldMock = new MockFor(Field) def mb = new MyBean() fieldMock.demand.get(mb) { throw new IllegalAccessException("haha") } fieldMock.use { Field f = MyBean.class.getDeclaredField("name") shouldFail(IllegalAccessException) { f.get(mb) } } } } class MyBean { def name = "hello, groovy" }
That's it. It is ridiculous how easy Groovy makes mocking any object. The steps are basically:
- Create mock using
MockFor
- Tell mock what to do using
demand
- Execute code under test in a closure passed to
use
Developers used to the power of dynamic languages like Ruby of course won't think too much of this as it is even simpler to create mocks, but this is something new for Java developers. Now there is really almost no reason why you can't test literally all of your Java code, and more importantly, do it very easily.