JMockit原理剖析 -Exepectations录制原理
Exepectations的使用频率太高了,我们用它来录制调用以及调用返回结果。可是它背后是怎么工作的呢。
以如何对类Mock中提到测试ClassMockingByExpectationsTest为例,在这个测试程序中,我们对AnOrdinaryClass进行了Mock,
那JMockit到底对AnOrdinaryClass重定义后的类是什么样子呢? 通过一些反编译工具,我们抓取到的反编译代码如下:
public class AnOrdinaryClass {
public AnOrdinaryClass() {
if (RecordAndReplayExecution.recordOrReplay(this, 1, "cn/jmockit/demos/AnOrdinaryClass", "<init>()V", (String)null, 1, (Object[])null) == Void.class) {
TestRun.lineExecuted(0, 4);
}
}
public static int staticMethod() {
Object var10000 = RecordAndReplayExecution.recordOrReplay((Object)null, 9, "cn/jmockit/demos/AnOrdinaryClass", "staticMethod()I", (String)null, 1, (Object[])null);
if (var10000 != Void.class) {
return (Integer)var10000;
} else {
TestRun.lineExecuted(0, 7);
return 1;
}
}
public int ordinaryMethod() {
Object var10000 = RecordAndReplayExecution.recordOrReplay(this, 1, "cn/jmockit/demos/AnOrdinaryClass", "ordinaryMethod()I", (String)null, 1, (Object[])null);
if (var10000 != Void.class) {
return (Integer)var10000;
} else {
TestRun.lineExecuted(0, 12);
return 2;
}
}
public final int finalMethod() {
Object var10000 = RecordAndReplayExecution.recordOrReplay(this, 17, "cn/jmockit/demos/AnOrdinaryClass", "finalMethod()I", (String)null, 1, (Object[])null);
if (var10000 != Void.class) {
return (Integer)var10000;
} else {
TestRun.lineExecuted(0, 17);
return 3;
}
}
public native int navtiveMethod();
private int privateMethod() {
TestRun.lineExecuted(0, 25);
return 5;
}
public int callPrivateMethod() {
Object var10000 = RecordAndReplayExecution.recordOrReplay(this, 1, "cn/jmockit/demos/AnOrdinaryClass", "callPrivateMethod()I", (String)null, 1, (Object[])null);
if (var10000 != Void.class) {
return (Integer)var10000;
} else {
TestRun.lineExecuted(0, 30);
return this.privateMethod();
}
}
}
我们发现,每一个方法除了native,方法的第一行都置入一行调用:RecordAndReplayExecution.recordOrReplay。
因此,录制和重放的奥秘就封装在这个方法RecordAndReplayExecution.recordOrReplay中啦。下面我们重点分析下RecordAndReplayExecution.recordOrReplay这个方法到底做了什么事情。
方法定义如下,感兴趣的同学,也可以下载JMockit的源代码,找到RecordAndReplayExecution.recordOrReplay这个方法
/**
*
* @param mock:即Expectation/Verfication脚本中是Mock对象/类,
* @param classDesc:即Expectation/Verfication脚本中是Mock对象/类的描述
* @param mockDesc: 即录制/重放/验证的方法的描述
@executionModeOrdinal: ExecutionMode.Regular(如果是mocked) ExecutionMode.PerInstance(如果是Injectable)
@param args 即录制/重放/验证的方法的入参
*/
public static Object recordOrReplay(@Nullable Object mock, int mockAccess, @Nonnull String classDesc,
@Nonnull String mockDesc,
@Nullable String genericSignature, int executionModeOrdinal, @Nullable Object[] args) throws Throwable {
看到了没,通过不同测试阶段RecordPhase(录制阶段),ReplayPhase(重放阶段),BaseVerificationPhase(校验阶段)对调用的记录,执行,验证,一环扣一环地,就实现了JMockit录制,回放,验证的程序逻辑。
RecordAndReplayExecution.recordOrReplay的代码建议您多看看。对JMockit程序会有更清楚的认识。