Suppose you wish to test a class which is dependent on a static call. Is there a way to mock out that call?
Yes, there are two suggested approaches:
- Using EMC
- Using JMockit (requires Java 6)
Using EMC
Here we are calling Arrays.sort() directly - normally that would be the problematic code within your class under test.
// non-mocked first to prove it works normally String[] things = ['dog', 'ant', 'bee', 'cat'] Arrays.sort(things) println things // => {"ant", "bee", "cat", "dog"} Arrays.metaClass.'static'.sort = { a -> a[0] = 'ewe' a[1] = 'fox' } things = ['dog', 'ant', 'bee', 'cat'] Arrays.sort(things) println things // => {"ewe", "fox", "bee", "cat"}
More details about this approach: ExpandoMetaClass - Adding static methods
Using JMockit
If you are in a position to use Java 6, you should also consider using JMockit.
// require(url:'https://jmockit.dev.java.net', jar='jmockit.jar') // require(url:'https://jmockit.dev.java.net', jar='jmockit-asm2.jar') // needs to be run with "-javaagent:jmockit.jar" // and "-Xbootclasspath/a:jmockit.jar;.;jmockit-asm2.jar" // The bootclasspath option is only required because we are mocking // a class from the java.* package (part of the bootclasspath for Java) import mockit.Mockit // non-mocked first to show normal case String[] things = ['dog', 'ant', 'bee', 'cat'] Arrays.sort(things) println things // => {"ant", "bee", "cat", "dog"} Mockit.redefineMethods(Arrays, MockArrays) things = ['dog', 'ant', 'bee', 'cat'] Arrays.sort(things) println things // => {"dog", "elk", "ape", "cat"}
Where MockArrays is the following Java class:
// Java public class MockArrays { public static void sort(Object[] a) { a[1] = "elk"; a[2] = "ape"; } }
We use a Java class here because otherwise JMockit tries to replace other GroovyObject methods (e.g. getMetaClass, invokeMethod, ...) and won't find them inside the java.util.Arrays class. Obviously, if your redefining a Groovy class, you can use another Groovy class.
More details: Using JMockit with Groovy.