JMockit 入门
2025/5/20大约 2 分钟
本文示例在 Java 8 中测试通过。
引入依赖
jmockit 的最新版本,必须要指定 -javaagent ,这对一些IDE并不友好。比如在 Intellij IDEA 中无法直接使用右键菜单运行测试类。
如果使用 gradle 构建项目,在 build.gradle 中增加以下配置:
dependencies {
testCompile "junit:junit:4.12"
testCompile "org.jmockit:jmockit:1.46"
}
test {
// jvmArgs "-javaagent:${classpath.find { it.name.contains("jmockit") }.absolutePath}"
jvmArgs "-javaagent:${configurations.testRuntimeClasspath.find { it.name.contains('jmockit') }}"
testLogging {
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
对于老版本gradle+jmockit,一般不用指定 jvmArgs 。
若遇到报错 JMockit didn't get initialized; please check the -javaagent JVM initialization parameter was used,说明需要指定下 jvmArgs。
若 jvmArgs 指定后报错 Cannot change dependencies of configuration ':xxx' after it has been included in dependency resolution. 。那么可以换成下面的方式,保证在依赖解析前加上参数:
test {
doFirst {
jvmArgs "-javaagent:${configurations.testRuntimeClasspath.find { it.name.contains('jmockit') }}"
}
}
使用 Expectations 给返回值打桩
package demo;
import mockit.*;
import org.junit.Test;
import java.util.Random;
public class MyJMockitoDemo {
@Mocked
Random mockRandom;
@Test
public void test01() {
System.out.println("----test01----");
System.out.println(mockRandom.nextInt());
// 指明调用 nextInt 时,返回 123
new Expectations() {{ // 通过双大括号构造匿名类,并初始化对象
mockRandom.nextInt(); result = 123;
}};
System.out.println(mockRandom.nextInt());
}
@Test
public void test02() {
System.out.println("----test02----");
System.out.println(mockRandom.nextInt());
}
}
在命令行中执行gradle test
,效果如下::
$ gradle test
> Task :test
demo.MyJMockitoDemo > test01 STANDARD_OUT
----test01----
0
123
demo.MyJMockitoDemo > test02 STANDARD_OUT
----test02----
0
关于双大括号,可以参考 [[1024-Java 匿名类双大括号初始化]]。
使用 MockUp 给返回值打桩
package demo;
import mockit.*;
import org.junit.Test;
import java.util.Random;
public class MyJMockitoDemo {
@Test
public void test01() {
System.out.println("----test01----");
Random random = new Random();
System.out.println(random.nextInt()); // 输出一个随机数
new MockUp<Random>() {
@Mock
public int nextInt() {
return 1;
}
};
System.out.println(random.nextInt()); // 输出 1
}
@Test
public void test02() {
System.out.println("----test02----");
Random random = new Random();
System.out.println(random.nextInt()); // 输出一个随机数
}
}
在命令行中执行gradle test
,效果如下:
$ gradle test
> Task :test
demo.MyJMockitoDemo > test01 STANDARD_OUT
----test01----
-377985168
1
demo.MyJMockitoDemo > test02 STANDARD_OUT
----test02----
1201440410
MockUp 可以给静态方法打桩
Calculate 类中增加静态方法 add :
package demo;
public class Calculate {
// 注意,这是一个 static 函数
public static int add(int a, int b) {
return a+b;
}
}
测试类代码:
package demo;
import mockit.*;
import org.junit.Test;
public class MyJMockitoDemo {
@Test
public void test() {
new MockUp<Calculate>() {
@Mock
public int add(int a, int b) { // 这里不用 static 修饰函数
return 100;
}
};
System.out.println(Calculate.add(1, 2)); // 输出 100
}
}
在命令行中执行gradle test
,效果如下:
$ gradle test
> Task :test
demo.MyJMockitoDemo > test01 STANDARD_OUT
100
原理
基本原理是:通过 javaagent 机制,修改被测试类的字节码。