Mocking core Java classes with jmockit

I know, I know. Java. Blech!

But if you have to work in Java, instead of something more elegant like Ruby, wouldn’t you like some of the same awesome mocking power that you have come to know and love in Java? Yeah, me too.

Toby DiPasquale turned me on to jmockit. It’s a little framework that provide RSpec-like mocking in Java. To those familiar with RSpec: jmockit allows developers to mock constructors as well as individual method on live objects. It accomplishes this courtesy of the java.lang.instrument package that was added in Java 1.5.

I was curious to see if it is possible to mock boot classloader loaded classes (i.e., java.lang.Integer, etc.). After a few minutes of tinkering, I found a way but it’s none to pleasant…

The primary annoyance is this: the core Java mocks appear to have to be in the bootclasspath. Why? I speculate however I believe the JVM needs the definition when the class is initial loaded – which, for core classes, can often happen at startup.

So, for example, this works:

Test.java:

  import mockit.*;
  import java.math.*;

  public class Test {
    public static void main(String[] args) {
      Mockit.redefineMethods(BigDecimal.class, new BigDecimalMock());
      System.err.println(BigDecimal.ONE.add(BigDecimal.ONE));
    }
  }

BigDecimalMock.java:

  import java.math.*;

  public class BigDecimalMock {
    public BigDecimal add(BigDecimal v) {
      return new BigDecimal("42");
    }
  }

And run the whole beast with this:

  java -Xbootclasspath/a:jmockit.jar: -javaagent:jmockit.jar Test

So, yes, Virginia, it is possible to mock core classes. But does it suck? Hell, yes. To make this work practically would likely necessitate launching a separate VM so as to “scope” the mock to a particular test.

Fugly.

Posted by evan on Friday, May 02, 2008

blog comments powered by Disqus