51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1298|回复: 0
打印 上一主题 下一主题

[转贴] 单元测试框架和覆盖率统计原理简析(一)

[复制链接]
  • TA的每日心情
    无聊
    4 天前
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-4-1 11:03:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    一、背景介绍
      最近部门在推进质量标准化,通过标准化研发、交付、部署、运维等过程,减少缺陷率和返工率,提高整体的工作效率。而单元测试又是软件研发过程中的重要一环,此文可以帮助理解单元测试插件的运行过程,了解 mock 框架以及平台覆盖率统计相关的原理,从而更好更快地编写单元测试。
      二、 单元测试与敏捷开发
      在常规的测试环节中,可以较为笼统地作以下分类:
      ·单元测试:快速地检查一个类或极小范围内的功能
      · 冒烟测试:快速检查系统核心功能是否有明确缺陷
      · 集成测试:检查整个应用或系统的功能
      · 回归测试:检查变更代码是否破坏旧的功能
      · 黑盒测试:将整个系统看成一个黑盒进行不特定测试
      · 白盒测试:按照编码或运行细节,设计特定的测试过程
      完全没有实施过单元测试的团队,推进过程可以按照确定覆盖率基线、覆盖率摸底、持续补充用例、持续提升单元测试质量和覆盖率几个环节。最终的目的是希望研发人员从被动编写到主动编写,不断提升代码可测性,将低级缺陷扼杀在集成测试之前。

     从不写单元测试、不会写单元测试,到写单元测试、写有效的单元测试,可以从4个阶段来推进。

     三、Maven & JUnit 的关系
      1.Maven 的简介
      名词解释
      Maven 中有两个核心概念,phase 和 goal,先通过 IDEA 中的 Maven 面板,来直观地感受一下 phase 和 goal 的区别:
      1)goals
      goals 是属于具体 maven 插件的一个任务,可以完成一件具体的事情。例如在 Spring Boot 的官方插件中,就提供了 run 这个任务,帮助我们直接通过 maven 命令运行我们的 Spring Boot 应用。
      具体实践中,会将 goal 绑定在某个 phase 运行时执行。

    2)lifecycle 和 phase
      phase 是 Maven 定义的一套通用编译过程,例如 compile、deploy,phase 本身并没有具体行为,需要依赖相关插件绑定任务。

    可以通过在 pom 文件中的插件声明,指定某个 goal 运行的时机(phase)。
    1.  <executions>
    2.      <execution>
    3.         <goals>
    4.           <goal>repackage</goal>
    5.         </goals>
    6.         <phase>package</phase>
    7.      </execution>
    8.   </executions>
    复制代码
    三套生命周期
      Maven 的整体架构采用了 core + plugin 的方式,core 可以当成一个 Launcher,启动过程中会有一些切换主类的过程,Tomcat、Spring Boot、Pandora Boot 都有类似的设计。
      Maven 中定义了三套生命周期:clean、default、site,每个生命周期会包含一些阶段(phase)。三套生命周期相互独立,执行某个 phase 时,按序执行且顺序靠前 phase 先执行,直到指定的 phase 运行结束,之后的 phase 不会再执行。
      1)clean 生命周期
      目的是做一些构建文件的清理工作。
    1. pre-clean..............执行清理前的工作
    2.   clean..................清理上一次构建生成的所有文件
    3.   post-clean.............执行清理后的工作
    复制代码
     2)default 生命周期
      包含了最常用的 phase,定义了构建项目时的核心过程。
    1. validate
    2.   initialize
    3.   generate-sources
    4.   process-sources
    5.   generate-resources
    6.   process-resources......复制和处理资源文件到target目录,准备打包
    7.   compile................编译项目的源代码
    8.   process-classes
    9.   generate-test-sources
    10.   process-test-sources
    11.   generate-test-resources
    12.   process-test-resources
    13.   test-compile...........编译测试源代码
    14.   process-test-classes
    15.   test...................运行测试代码
    16.   prepare-package
    17.   package................打包成jar或者war或者其他格式的分发包
    18.   pre-integration-test
    19.   integration-test
    20.   post-integration-test
    21.   verify
    22.   install................将打好的包安装到本地仓库,供其他项目使用
    23.   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。

    在收集到所有的插件信息后,会按照 phase 顺序依次执行。

     2.单元测试框架 JUnit
      JUnit 是 Java 开发测试中最常用的单元测试框架,它是由 Kent Beck (极限编程和测试驱动开发的创始人) 和 Erich Gamma 共同编写,其灵感来自于 Kent Beck 早期在 SUnit (一种针对 Smalltalk 编程语言的测试框架) 上的工作。
      JUnit 属于 xUnit测试框架家族。xUnit 家族中的测试框架通常会定义这几个运行过程: setup, exercise, verify, teardown。

    JUnit3 中我们能见到一些约定的类名和方法名,这是因为早期的 JDK 并不支持注解。直到 JDK 1.5 支持注解,才使得 JUnit4 基于注解声明测试用例变成可能。
      JUnit4 采用 @Annotation 标注的方式,比 JUnit3 的通过类继承和特定方法名带来更大的灵活性,而且只有一个 jar 包非常易于集成。

     JUnit5(2016)
      JUnit5 则诞生于一个互联网新技术大爆发的时期,它的目标是作为一个测试平台,来连接测试工具、测试引擎和用例。JUnit5 的主要组件可以分为。


    JUnit4 是如何被 Maven 唤起的
      前文提到,surefire 插件的会将测试任务绑定在 test 阶段,因此当运行 mvn test时会调用 surefire 插件的方法。surefire 通过 SPI 机制扫描类路径下,发现测试引擎实现类(需要实现 org.apache.maven.surefire.providerapi.SurefireProvider),从而将测试任务转嫁到具体的执行引擎 。

    按测试类名称过滤
      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 来运行。
    1.  <plugin>
    2.     <groupId>org.apache.maven.plugins</groupId>
    3.     <artifactId>maven-surefire-plugin</artifactId>
    4.     <version>2.16</version>
    5.     <dependencies>
    6.       <dependency>
    7.         <groupId>org.apache.maven.surefire</groupId>
    8.         <artifactId>surefire-junit4</artifactId>
    9.         <version>2.16</version>
    10.       </dependency>
    11.     </dependencies>
    12.   </plugin>
    复制代码
    这就是为什么在本地运行 IDEA 没问题, Aone 或者命令行运行就出错的原因,因为缺少依赖 Maven 无法识别 JUnit4 注解,导致很多变量没有被 @before 注解标注的方法初始化。











    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-25 07:59 , Processed in 0.070302 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表