51Testing软件测试论坛
标题:
单元测试框架和覆盖率统计原理简析(一)
[打印本页]
作者:
lsekfe
时间:
2022-4-1 11:03
标题:
单元测试框架和覆盖率统计原理简析(一)
一、背景介绍
最近部门在推进质量标准化,通过标准化研发、交付、部署、运维等过程,减少缺陷率和返工率,提高整体的工作效率。而单元测试又是软件研发过程中的重要一环,此文可以帮助理解单元测试插件的运行过程,了解 mock 框架以及平台覆盖率统计相关的原理,从而更好更快地编写单元测试。
二、 单元测试与敏捷开发
在常规的测试环节中,可以较为笼统地作以下分类:
·单元测试:快速地检查一个类或极小范围内的功能
· 冒烟测试:快速检查系统核心功能是否有明确缺陷
· 集成测试:检查整个应用或系统的功能
· 回归测试:检查变更代码是否破坏旧的功能
· 黑盒测试:将整个系统看成一个黑盒进行不特定测试
· 白盒测试:按照编码或运行细节,设计特定的测试过程
完全没有实施过单元测试的团队,推进过程可以按照确定覆盖率基线、覆盖率摸底、持续补充用例、持续提升单元测试质量和覆盖率几个环节。最终的目的是希望研发人员从被动编写到主动编写,不断提升代码可测性,将低级缺陷扼杀在集成测试之前。
[attach]137131[/attach]
从不写单元测试、不会写单元测试,到写单元测试、写有效的单元测试,可以从4个阶段来推进。
[attach]137132[/attach]
三、Maven &
JUnit
的关系
1.Maven 的简介
名词解释
Maven 中有两个核心概念,phase 和 goal,先通过 IDEA 中的 Maven 面板,来直观地感受一下 phase 和 goal 的区别:
1)goals
goals 是属于具体 maven 插件的一个任务,可以完成一件具体的事情。例如在 Spring Boot 的官方插件中,就提供了 run 这个任务,帮助我们直接通过 maven 命令运行我们的 Spring Boot 应用。
具体实践中,会将 goal 绑定在某个 phase 运行时执行。
[attach]137133[/attach]
2)lifecycle 和 phase
phase 是 Maven 定义的一套通用编译过程,例如 compile、deploy,phase 本身并没有具体行为,需要依赖相关插件绑定任务。
[attach]137134[/attach]
可以通过在 pom 文件中的插件声明,指定某个 goal 运行的时机(phase)。
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
复制代码
三套生命周期
Maven 的整体架构采用了 core + plugin 的方式,core 可以当成一个 Launcher,启动过程中会有一些切换主类的过程,Tomcat、Spring Boot、Pandora Boot 都有类似的设计。
Maven 中定义了三套生命周期:clean、default、site,每个生命周期会包含一些阶段(phase)。三套生命周期相互独立,执行某个 phase 时,按序执行且顺序靠前 phase 先执行,直到指定的 phase 运行结束,之后的 phase 不会再执行。
1)clean 生命周期
目的是做一些构建文件的清理工作。
pre-clean..............执行清理前的工作
clean..................清理上一次构建生成的所有文件
post-clean.............执行清理后的工作
复制代码
2)default 生命周期
包含了最常用的 phase,定义了构建项目时的核心过程。
validate
initialize
generate-sources
process-sources
generate-resources
process-resources......复制和处理资源文件到target目录,准备打包
compile................编译项目的源代码
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
test-compile...........编译测试源代码
process-test-classes
test...................运行测试代码
prepare-package
package................打包成jar或者war或者其他格式的分发包
pre-integration-test
integration-test
post-integration-test
verify
install................将打好的包安装到本地仓库,供其他项目使用
deploy.................将打好的包安装到远程仓库,供其他项目使用
复制代码
3)site 生命周期
pre-site
site...................生成项目的站点文档
post-site
site-deploy............发布生成的站点文档
mvn test 和 mvn surefire:test
surefire:test 是 maven-surefire-plugin 中定义的一个任务,默认绑定在 test 阶段运行
·
当运行 mvn test命令时,先运行 test 阶段之前的 compile、test-compile 等 phase 及绑定 goal 任务;
·
而 mvn surefire:test 则是直接运行这个任务,不会执行编译,因此需要提前手动编译好源代码和测试代码;
Maven 会自动收集当前项目的所有模块,做依赖树和插件合并。当 pom 中未声明任何插件或者插件版本号为空,Maven 会使用默认值进行填充。
maven 的 default 生命周期和插件版本关系的声明文件:maven-core-3.6.3.jar/META-INF/plexus/default-bindings.xml。
[attach]137135[/attach]
在收集到所有的插件信息后,会按照 phase 顺序依次执行。
[attach]137136[/attach]
2.单元测试框架 JUnit
JUnit 是 Java 开发测试中最常用的单元测试框架,它是由 Kent Beck (极限编程和测试驱动开发的创始人) 和 Erich Gamma 共同编写,其灵感来自于 Kent Beck 早期在 SUnit (一种针对 Smalltalk 编程语言的测试框架) 上的工作。
JUnit 属于 xUnit测试框架家族。xUnit 家族中的测试框架通常会定义这几个运行过程: setup, exercise, verify, teardown。
[attach]137137[/attach]
JUnit3 中我们能见到一些约定的类名和方法名,这是因为早期的 JDK 并不支持注解。直到 JDK 1.5 支持注解,才使得 JUnit4 基于注解声明测试用例变成可能。
JUnit4 采用 @Annotation 标注的方式,比 JUnit3 的通过类继承和特定方法名带来更大的灵活性,而且只有一个 jar 包非常易于集成。
[attach]137138[/attach]
JUnit5(2016)
JUnit5 则诞生于一个互联网新技术大爆发的时期,它的目标是作为一个测试平台,来连接测试工具、测试引擎和用例。JUnit5 的主要组件可以分为。
[attach]137139[/attach]
[attach]137140[/attach]
JUnit4 是如何被 Maven 唤起的
前文提到,surefire 插件的会将测试任务绑定在 test 阶段,因此当运行 mvn test时会调用 surefire 插件的方法。surefire 通过 SPI 机制扫描类路径下,发现测试引擎实现类(需要实现 org.apache.maven.surefire.providerapi.SurefireProvider),从而将测试任务转嫁到具体的执行引擎 。
[attach]137141[/attach]
按测试类名称过滤
Maven Surefire 插件无其他测试框架的依赖注入时,默认使用 JUnit3Provider 作为执行引擎,因此要求测试类命名为以下模式:
·
**/Test*.java
·
**/*Test.java
·
**/*Tests.java
*
·
*/*TestCase.java
过程中会排除所有嵌套类(包括静态成员类),也可以通过在 pom 文件中配置include和exclude规则来覆盖默认行为。
默认引擎下扫描测试方法的规则:
·
测试方法必须是 public, 非 static,返回类型为 void,无参的方法;
·
测试方法必须写成testXxx形式;
·
全局变量可以在无参的构造方法中初始化;
·
每次执行一个测试用例前,执行一遍setUp(),用于对数据的初始化;执行完一个测试用例后,再执行tearDown(),用于销毁还原数据;
因此当我们需要使用 JUnit4 的注解如 @Before,需要添加依赖 surefire-junit4 告诉 SurefirePlugin 优先使用 JUnit4 的
@runner
来运行。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit4</artifactId>
<version>2.16</version>
</dependency>
</dependencies>
</plugin>
复制代码
这就是为什么在本地运行 IDEA 没问题, Aone 或者命令行运行就出错的原因,因为缺少依赖 Maven 无法识别 JUnit4 注解,导致很多变量没有被
@before
注解标注的方法初始化。
欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/)
Powered by Discuz! X3.2