青年IT男

个人从事金融行业,就职过易极付、思建科技等重庆一流技术团队,目前就职于某网约车平台负责整个支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、人工智能等领域。

JMockit原理剖析 -Exepectations录制原理

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程序会有更清楚的认识。

0
1028826685@qq.com