##什么是Emma?

EMMA 是一个用于检测和报告 JAVA 代码覆盖率的开源工具。它不但能很好的用于小型项目,很方便得得出覆盖率报告,而且适用于大型企业级别的项目。

本篇教程写给不愿意看emma userguide文档的兔子们,主要目标是给没有接触过emma的人一个可以成功运行的实例,傻瓜式教程。


##准备工作

  • 下载emma文件 【下载地址
  • 解压下载下来的文件 将lib/文件夹下的emma.jar放到你电脑的jre文件夹的/lib/ext/文件夹下,也可能是jdk文件夹的jre/lib/ext文件夹下,取决于你的电脑使用的是jre还是jdk。也可以每次运行的时候把emma.jar的路径加到命令中,不过太繁琐了。

##Emma on-the-fly模式
Emma 有两种运行模式,一种是on-the-fly模式,一种是offline模式。

On the fly 模式往加载的类中加入字节码,相当于用 EMMA 实现的 application class loader 替代原来的 application class loader。
Offline 模式在类被加载前,加入字节码

1
2
3
4
5
6
7
8
<!-- 首先用终端cd到下载下来的emma文件夹的examples文件目录 -->
$ mkdir out
$ javac -d out -g src/*.java src/search/*.java src/search/*.java
$ java -cp out Main
main(): running doSearch()...
main(): done
<!-- 将emmarun命令放在 main类之前 -->
$java emmarun -cp out Main

用户手册上的这个命令会报错,emma有好几年没有更新了,因此当java7出来后有一些新的特性,emma没有能够及时支持,使用下面的命令可以成功运行,具体可以看【StackOverflow上的解释】,下文中也有些命令需要这个参数

1
$ java -XX:-UseSplitVerifier emmarun -cp out Main

完成上一步后应该可以看到如下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[EMMA v2.0.5312 report, generated Thu Dec 25 21:40:41 CST 2014]
-------------------------------------------------------------------------------
OVERALL COVERAGE SUMMARY:
[class, %] [method, %] [block, %] [line, %] [name]
100% (3/3) 100% (7/7) 95% (120/126) 90% (27/30) all classes
OVERALL STATS SUMMARY:
total packages: 2
total classes: 3
total methods: 7
total executable files: 3
total executable lines: 30
COVERAGE BREAKDOWN BY PACKAGE:
[class, %] [method, %] [block, %] [line, %] [name]
100% (2/2) 100% (4/4) 91% (64/70) 84% (16/19) search
100% (1/1) 100% (3/3) 100% (56/56) 100% (11/11) default package
-------------------------------------------------------------------------------


##Emma offline模式
在offline模式下,emma的功能分成了几个子命令:instr,mergereport

###1.插装
instrument在测试中是插装的意思。

当你运行一段代码时,你如何判断哪些语句、条件、分支、路径执行过了?如果这个都不能判断,那覆盖率无从谈起。
代码插装就是在要测的代码中插入你写的一些代码,可以是(但不限于)打印语句等。知道了代码中哪些部分已经执行过了,那我们就可以有的放矢,针对没有覆盖到的语句、条件、分支、条件分支、路径等补充用例以达到更充分的覆盖。

1
2
3
4
5
6
7
8
9
10
<!-- 和上面一样,用终端cd到下载下来的emma文件夹的examples文件目录 为了保险起见
,将插装后生成的.class文件放在另一个文件中-->
$ mkdir out
$ javac -d out -g src/*.java src/search/*.java src/search/*.java
$ mkdir outinstr
$ java emma instr -d outinstr -ip out
EMMA: processing instrumentation path ...
EMMA: instrumentation path processed in 116 ms
EMMA: [3 class(es) instrumented, 0 resource(s) copied]
EMMA: metadata merged into [...coverage.em] {in 31 ms}

此步骤完成后,会生成coverage.em文件,教程中讲是dump出来的类的元数据(metadata)。

###2.执行
运行插装后的程序

1
2
3
4
5
$ java -XX:-UseSplitVerifier -cp outinstr;out Main
EMMA: collecting runtime coverage data ...
main(): running doSearch()...
main(): done
EMMA: runtime coverage data merged into [...coverage.ec] {in 32 ms}

此步骤完成后,会生成coverage.ec文件,当JVM退出时,EMMA将运行时覆盖轮廓(runtime coverage profile),写进该文件中。
注意此命令中的classpath:outinstr;out,插装的类必须放在第一个,因为instr命令时没有复制无法执行的东西,如接口和资源,因此原始的out文件夹应该放在outinstr文件夹后。

###3.生成报告
此步骤将类的原数据和运行时的覆盖轮廓结合起来生成一个txt形式的报告和一个html形式的报告。

1
2
3
4
$ java emma report -r txt,html -in coverage.em -in coverage.ec
EMMA: 2 file(s) read and merged in 43 ms
EMMA: writing [txt] report to [...coverage.txt] ...
EMMA: writing [html] report to [...coverage/index.html] ...

###可选操作:合并
可以将生成的文件合并成一个。

1
2
3
4
$ java emma merge -in coverage.em -in coverage.ec -out coverage.es
EMMA: processing input files ...
EMMA: 2 file(s) read and merged in 42 ms
EMMA: merged/compacted data written to [...coverage.es] {in 58 ms}

###运行结果
运行完以上命令后可以查看生成的html覆盖率结果分析如下:
覆盖率html报告


#参考文献