软件自动化测试基础知识

JAVA覆盖率统计之01-Jacoco控制流案例

2018-07-01  本文已影响32人  antony已经被占用

字节码注入与控制流

1 注入方式
JaCoCo是一个被广泛使用的JAVA覆盖率统计工具,它利用ASM库,通过注入字节码的方式来修改和生成java字节码,从而记录程序的执行数据,但它不会改变原有代码的行为。 最常用的方式是通过Java Agent以On-The-Fly的方式在runtime来注入和统计数据。这种方式就不会改变编译的class文件。


implementation.png

当然在本文中,笔者将介绍Jacoco的具体注入方式,因此,我们使用Jaccoco Offline 的模式,在编译时直接将覆盖率统计的探针(Probe)注入(Inject)到被打桩的class文件中。

2 Probe探针组成
Jacoco是通过一个Probe探针的方式来注入的,探针是字节指令集插入到java方法中,程序执行后可以被记录,它不会改变原有代码的行为。
根据Jacoco官方介绍,一个Probe可以由以下JVM指令组成:

JVM指令 Probe作用 说明
ALOAD probearray 将一个引用类型本地变量推送至栈顶
xPUSH probeid 将一个常量值推送至栈顶
ICONST_1 将int型推送至栈顶
BASTORE 从操作数栈存存储到数组

根据代码逻辑的不同,可以由如下的一些变化:

Possible Opcodes Min. Size [bytes] Max. Size [bytes]
ALOAD_x, ALOAD * 1 2
ICONST_x, BIPUSH, SIPUSH, LDC, LDC_W ** 1 3
ICONST_1 1 1
BASTORE 1 1
Total: 4 7

感兴趣的读者可以阅读以下链接了解更多

https://www.jacoco.org/jacoco/trunk/doc/flow.html

3 Probe探针插入策略
JaCoCo是根据控制流Type来采用不同的探针插入策略的。探针不改变该方法的行为,但记录他们已被执行的事实,从理论上讲,可以在控制流图的每一个边插入一个探针,作为探针实现本身需要多个字节码指令,这将增加几倍的类文件的大小和执行速度。事实上,只需要一个几个探头,根据每个方法的控制流的方法。具体策略如下:

sequence.JPG
jump.JPG
return.JPG

案例

以下案例来介绍IF/FOR/抛异常等场景下jacoco是如何进行注入的。

package com.demo.jacoco;
public class DemoClass {
    public static void callIf(boolean flag) {
        print("start");
        if(flag) {
            print("true");
        }else {
            print("flase");
        }
        print("done");
    }
    private static void print(String string) {
        System.out.println(string);
    }
    
    public static void callFor(int loop) {
        for(int i=0;i<loop;i++)
            print("hi");
    }
    public static void callThrow(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们通过javap 来解析DemoClass.class

javap -v -c DemoClass.class

1 IF

![](https://img.haomeiwen.com/i2651525/0a155f5b1d9281a4.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2 FOR

jacoco_for.JPG

3 Throw

jacoco_throw.JPG

4 默认构造方法

jacoco_1类构造方法.JPG
上一篇下一篇

猜你喜欢

热点阅读