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.
| Code Block |
|---|
// 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.
| Code Block |
|---|
// 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:
| Code Block |
|---|
// 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.