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:

  1. Create mock using MockFor
  2. Tell mock what to do using demand
  3. 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.



Comments:

On my To Do list is to take a careful look at unit testing in Groovy: specifically, can I unit test my Java code using Groovy's unit testing capabilities, and would I want to? Unit tests are a great place for dynamic scripting languages: you're going to be running all of them often, so you're not actually losing anything when you lose static typing, and anything that can make data mocking and set-up easier becomes a huge win.

My biggest concern would be whether code coverage tools would work with Groovy. Any experience on that?

Posted by Robert Fischer on June 01, 2007 at 04:42 AM EDT #

I've just started doing this myself, so I don't know too much yet, other than how quickly I was able to whip up those mocks without really knowing Groovy very well. On my current project we are looking at starting to write tests in Groovy but first have to make sure it all works with Maven2, which we're using as the build tool.

I know, based on talking to other people who are doing it like Neal Ford of ThoughtWorks, that you definitely can unit test your Java code using Groovy, even though I've not yet done that. I am fairly sure the coverage tools will work fine since they are instrumenting your actual Java code, not the tests themselves, so as long as a LOC is executed, Clover, Cobertura, etc. will pick that fact up. And, I know that Neal is huge into delivering systems with close to 100% coverage, so I doubt he'd use Groovy for tests if he couldn't get test coverage. (I am hoping to sneak my laptop to the beach next week and play around with Groovy some more, which pretty much makes me a total geek.)

Posted by Scott Leberknight on June 04, 2007 at 06:00 PM EDT #

Post a Comment:
Comments are closed for this entry.