作者:
wanwei | 15 min (4174 words)

浅谈代码覆盖率

MacDown logo

引言

经常有人问这样的问题:“我们在做单元测试,那测试覆盖率要到多少才行?”。答案其实很简答,“作为指标的测试覆盖率都是没有用处的。”

Martin Fowler(重构那本书的作者)曾经写过一篇博客来讨论这个问题,他指出:把测试覆盖作为质量目标没有任何意义,而我们应该把它作为一种发现未被测试覆盖的代码的手段。

MacDown logo

代码覆盖率的意义

代码覆盖率的意义

目前 Java 常用覆盖率工具 Jacoco、Emma 和 Cobertura

MacDown logo

覆盖率工具工作流程

MacDown logo

  1. 对 Java 字节码进行插桩,On-The-Fly 和 Offine 两种方式。
  2. 执行测试用例,收集程序执行轨迹信息,将其 dump 到内存。
  3. 数据处理器结合程序执行轨迹信息和代码结构信息分析生成代码覆盖率报告。
  4. 将代码覆盖率报告图形化展示出来,如 html、xml 等文件格式。

插桩原理

MacDown logo

主流代码覆盖率工具都采用字节码插桩模式,通过钩子的方式来记录代码执行轨迹信息。其中字节码插桩又分为两种模式 On-The-Fly 和 Offine。On-The-Fly 模式优点在于无需修改源代码,可以在系统不停机的情况下,实时收集代码覆盖率信息。Offine 模式优点在于系统启动不需要额外开启代理,但是只能在系统停机的情况下才能获取代码覆盖率。 基于以上特性,同时由于公司使用 JDK8,我们采用 Jacoco 来获取集成测试代码覆盖率,单元测试使用 Cobertura。

On-The-Fly 插桩 Java Agent

On-The-Fly 插桩 Class Loader

Offine 插桩

On-The-Fly 和 Offine 比较

实践应用

单元测试覆盖率

目前有赞开发人员会写单元测试用例,为了能够引入持续集成,我们选取了 Sonar+Cobertura 来获取单元测试覆盖率。 我们将代码覆盖率绑定到代码编译阶段,这样每次代码编译就能够执行单元测试同时获取代码单元测试覆盖率

<plugin>  
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <version>2.7</version>
    <configuration>
        <formats>
            <format>xml</format>
        </formats>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>cobertura</goal>
            </goals>
        </execution>
    </executions>
</plugin>  
}

生成代码覆盖率文件以后,通过 Jenkins SonarQube Scanner 或者执行 mvn sonar:sonar 将该文件上传至 Sonar 服务器,就可以解析该文件,生成图形化的界面

MacDown logo

三、集成测试覆盖率

测试人员执行集成测试测试用例时(包括手工执行和自动化执行),我们需要代码覆盖率来发现测试用例设计的遗漏,及时补充用例来覆盖未被覆盖到的代码。

被测系统,在服务启动时,都会通过 javaagent 的方式做 On-The-Fly 插桩
MacDown logo

MacDown logo

获取代码覆盖率报告之后,结合 git 获取的本次代码变动信息,得到测试用例覆盖的变动文件的测试覆盖率统计信息。来分析是否有由于测试用例设计遗漏导致的代码没有覆盖或者是开发的无效代码导致该代码无法被覆盖,如果测试用例设计有所遗漏,可以对照的增加相应的用例;如果是无效代码可以删除。

自动化集成流程

MacDown logo

  1. 业务开发完成之后,开发人员做单元测试,单元测试完成之后,保证单元测试全部通过同时单元测试代码覆盖率达到一定程度(这个需要开发和测试约定,理论上越高越好),开发提测。

  2. 测试人员根据测试用例进行测试(包括手工测试和自动化测试),结合 git 获取本次变动代码的覆盖率信息。行覆盖率需达到 100%,分支达到 50% 以上,这个需要具体场景具体分析。

  3. 测试通过之后,代码合并至主干,进行自动化回归。

  4. 回归测试通过之后,代码可以上线。

基于这套流程,我们可以将单元测试代码覆盖率和集成测试代码覆盖率整合到持续集成流程中,如果代码覆盖率达不到我们设置的某个值时,可以终止流程继续下去获取需要人工确认之后,继续流程。

总结

本文主要介绍了 Java 代码覆盖率统计原理以及结合有赞测试的工程实践介绍了代码覆盖率该如何应用的实际测试中。不管是白盒测试还是黑盒测试,代码覆盖率统计都是必不可少的一环,它可以直接反映本次测试的遗漏点(不是 100% 反映)。结合到自动发布场景也是一个较好地衡量指标。

原文链接

欢迎关注我们的公众号
MacDown logo

欢迎大家一起来交流呀


↙↙↙阅读原文可查看相关链接,并与作者交流