欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

关于《JUnit5学习》系列

《JUnit5学习》系列旨在通过实战提升SpringBoot环境下的单元测试技能,一共八篇文章,链接如下:

  1. 基本操作
  2. Assumptions类
  3. Assertions类
  4. 按条件执行
  5. 标签(Tag)和自定义注解
  6. 参数化测试(Parameterized Tests)基础
  7. 参数化测试(Parameterized Tests)进阶
  8. 综合进阶(终篇)

本篇概览

本文是《JUnit5学习》系列的第一篇,通过实战学习在SpringBoot框架下JUnit5的基本功能,全篇章节如下:

  1. JUnit5简介
  2. SpringBoot对JUnit5的依赖
  3. 常用注解简介
  4. 5版本已废弃的注解介绍
  5. 进入实战环节,先介绍版本和环境信息
  6. 创建《JUnit5学习》系列源码的父工程
  7. 创建子工程,编码体验常用注解

关于JUnit5

  1. JUnit是常用的java单元测试框架,5是当前最新版本,其整体架构如下(图片来自网络):
  2. 从上图可见,整个JUnit5可以划分成三层:顶层框架(Framework)、中间的引擎(Engine),底层的平台(Platform);
  3. 官方定义JUnit5由三部分组成:Platform、Jupiter、Vintage,功能如下;
  4. Platform:位于架构的最底层,是JVM上执行单元测试的基础平台,还对接了各种IDE(例如IDEA、eclipse),并且还与引擎层对接,定义了引擎层对接的API;
  5. Jupiter:位于引擎层,支持5版本的编程模型、扩展模型;
  6. Vintage:位于引擎层,用于执行低版本的测试用例;
  • 可见整个Junit Platform是开放的,通过引擎API各种测试框架都可以接入;

SpringBoot对JUnit5的依赖

  1. 这里使用SpringBoot版本为2.3.4.RELEASE,在项目的pom.xml中依赖JUnit5的方法如下:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
  1. 如下图红框,可见JUnit5的jar都被spring-boot-starter-test间接依赖进来了:

曾经的RunWith注解

  1. 在使用JUnit4的时候,咱们经常这么写单元测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class XXXTest {
  1. 对于上面的RunWith注解,JUnit5官方文档的说法如下图红框所示,已经被ExtendWith取代:
  2. 咱们再来看看SpringBootTest注解,如下图,可见已经包含了ExtendWith:
  3. 综上所述,SpringBoot+JUnit5时,RunWith注解已经不需要了,正常情况下仅SpringBootTest注解即可,如果对扩展性有更多需求,可以添加ExtendWith注解,如下图:

常用的JUnit5注解(SpringBoot环境)

注意,接下来提到的测试方法,是指当前class中所有被@Test、@RepeatedTest、@ParameterizedTest、@TestFactory修饰的方法;

  1. ExtendWith:这是用来取代旧版本中的RunWith注解,不过在SpringBoot环境如果没有特别要求无需额外配置,因为SpringBootTest中已经有了;
  2. Test:被该注解修饰的就是测试方法;
  3. BeforeAll:被该注解修饰的必须是静态方法,会在所有测试方法之前执行,会被子类继承,取代低版本的BeforeClass;
  4. AfterAll:被该注解修饰的必须是静态方法,会在所有测试方法执行之后才被执行,会被子类继承,取代低版本的AfterClass;
  5. BeforeEach:被该注解修饰的方法会在每个测试方法执行前被执行一次,会被子类继承,取代低版本的Before;
  6. AfterEach:被该注解修饰的方法会在每个测试方法执行后被执行一次,会被子类继承,取代低版本的Before;
  7. DisplayName:测试方法的展现名称,在测试框架中展示,支持emoji;
  8. Timeout:超时时长,被修饰的方法如果超时则会导致测试不通过;
  9. Disabled:不执行的测试方法;

5版本已废弃的注解

以下的注解都是在5之前的版本使用的,现在已经被废弃:

被废弃的注解 新的继任者
Before BeforeEach
After AfterEach
BeforeClass BeforeAll
AfterClass AfterAll
Category Tag
RunWith ExtendWith
Rule ExtendWith
ClassRule RegisterExtension

版本和环境信息

整个系列的编码和执行在以下环境进行,供您参考:

  1. 硬件配置:处理器i5-8400,内存32G,硬盘128G SSD + 500G HDD
  2. 操作系统:Windows10家庭中文版
  3. IDEA:2020.2.2 (Ultimate Edition)
  4. JDK:1.8.0_181
  5. SpringBoot:2.3.4.RELEASE
  6. JUnit Jupiter:5.6.2
    接下来开始实战,咱们先建好SpringBoot项目;

关于lombok

为了简化代码,项目中使用了lombok,请您在IDEA中安装lombok插件;

源码下载

  1. 如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  1. 这个git项目中有多个文件夹,本章的应用在junitpractice文件夹下,如下图红框所示:

  2. junitpractice是父子结构的工程,本篇的代码在junit5experience子工程中,如下图:

创建Maven父工程

  1. 为了便于管理整个系列的源码,在此建立名为junitpractice的maven工程,后续所有实战的源码都作为junitpractice的子工程;
  2. junitpractice的pom.xml如下,可见是以SpringBoot的2.3.4.RELEASE版本作为其父工程:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><modules><module>simplebean</module><!--<module>testenvironment</module>--></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bolingcavalry</groupId><artifactId>junitpractice</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencyManagement><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency></dependencies></dependencyManagement>
</project>

本篇的源码工程

接下来咱们准备一个简单的SpringBoot工程用于做单元测试,该工程有service和controller层,包含一些简单的接口和类;

  1. 创建名为junit5experience的子工程,pom.xml如下,注意单元测试要依赖spring-boot-starter-test:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.bolingcavalry</groupId><artifactId>junitpractice</artifactId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath></parent><groupId>com.bolingcavalry</groupId><artifactId>junit5experience</artifactId><version>0.0.1-SNAPSHOT</version><name>junit5experience</name><description>Demo project for simplebean in Spring Boot junit5</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
  1. 写一些最简单的业务代码,首先是service层的接口HelloService.java:
package com.bolingcavalry.junit5experience.service;public interface HelloService {String hello(String name);int increase(int value);/*** 该方法会等待1秒后返回true,这是在模拟一个耗时的远程调用* @return*/boolean remoteRequest();
}
  1. 上述接口对应的实现类如下,hello和increase方法分别返回String型和int型,remoteRequest故意sleep了1秒钟,用来测试Timeout注解的效果:
package com.bolingcavalry.junit5experience.service.impl;import com.bolingcavalry.junit5experience.service.HelloService;
import org.springframework.stereotype.Service;@Service()
public class HelloServiceImpl implements HelloService {@Overridepublic String hello(String name) {return "Hello " + name;}@Overridepublic int increase(int value) {return value + 1;}@Overridepublic boolean remoteRequest() {try {Thread.sleep(1000);} catch (InterruptedException interruptedException) {interruptedException.printStackTrace();}return true;}
}
  1. 添加一个简单的controller:
package com.bolingcavalry.junit5experience.controller;import com.bolingcavalry.junit5experience.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@Autowiredprivate HelloService helloService;@RequestMapping(value = "/{name}", method = RequestMethod.GET)public String hello(@PathVariable String name){return helloService.hello(name);}
}
  1. 启动类:
package com.bolingcavalry.junit5experience;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Junit5ExperienceApplication {public static void main(String[] args) {SpringApplication.run(Junit5ExperienceApplication.class, args);}
}
  • 以上就是一个典型的web工程,接下来一起为该工程编写单元测试用例;

编写测试代码

  1. 在下图红框位置新增单元测试类:
  2. 测试类的内容如下,涵盖了刚才提到的常用注解,请注意每个方法的注释说明:
package com.bolingcavalry.junit5experience.service.impl;import com.bolingcavalry.junit5experience.service.HelloService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;@SpringBootTest
@Slf4j
class HelloServiceImplTest {private static final String NAME = "Tom";@AutowiredHelloService helloService;/*** 在所有测试方法执行前被执行*/@BeforeAllstatic void beforeAll() {log.info("execute beforeAll");}/*** 在所有测试方法执行后被执行*/@AfterAllstatic void afterAll() {log.info("execute afterAll");}/*** 每个测试方法执行前都会执行一次*/@BeforeEachvoid beforeEach() {log.info("execute beforeEach");}/*** 每个测试方法执行后都会执行一次*/@AfterEachvoid afterEach() {log.info("execute afterEach");}@Test@DisplayName("测试service层的hello方法")void hello() {log.info("execute hello");assertThat(helloService.hello(NAME)).isEqualTo("Hello " + NAME);}/*** DisplayName中带有emoji,在测试框架中能够展示*/@Test@DisplayName("测试service层的increase方法\uD83D\uDE31")void increase() {log.info("execute increase");assertThat(helloService.increase(1)).isEqualByComparingTo(2);}/*** 不会被执行的测试方法*/@Test@Disabledvoid neverExecute() {log.info("execute neverExecute");}/*** 调用一个耗时1秒的方法,用Timeout设置超时时间是500毫秒,* 因此该用例会测试失败*/@Test@Timeout(unit = TimeUnit.MILLISECONDS, value = 500)@Disabledvoid remoteRequest() {assertThat(helloService.remoteRequest()).isEqualTo(true);}
}
  1. 接下来执行测试用例试试,点击下图红框中的按钮:

  2. 如下图,在弹出的菜单中,点击红框位置:

  3. 执行结果如下,可见Displayname注解的值作为测试结果的方法名展示,超时的方法会被判定为测试不通过,Disable注解修饰的方法则被标记为跳过不执行:

  4. 在父工程junitpractice的pom.xml文件所在目录,执行mvn test命令,可以看到maven执行单元测试的效果:

  • 至此,咱们对SpringBoot环境下的JUnit5有了最基本的了解,接下来的章节会展开更多知识点和细节,对单元测试做更深入的学习。

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界…

JUnit5学习之一:基本操作相关推荐

  1. JUnit5学习之七:参数化测试(Parameterized Tests)进阶

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<JUnit5学习>系列 <JU ...

  2. JUnit5学习之二:Assumptions类

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<JUnit5学习>系列 <JU ...

  3. JUnit5学习之八:综合进阶(终篇)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<JUnit5学习>系列 <JU ...

  4. JUnit5学习之四:按条件执行

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<JUnit5学习>系列 <JU ...

  5. JUnit5学习之五:标签(Tag)和自定义注解

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<JUnit5学习>系列 <JU ...

  6. JUnit5学习之三:Assertions类

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<JUnit5学习>系列 <JU ...

  7. JUnit5学习之三:Assertions类,字节跳动视频面试分钟

    按条件执行 标签(Tag)和自定义注解 参数化测试(Parameterized Tests)基础 参数化测试(Parameterized Tests)进阶 综合进阶(终篇) 本篇概览 本文是<J ...

  8. c 语言学习:基本操作,数组,字符串,指针

    文章目录 基本操作 判断闰年平年 倒序输出五位数 赋值运算 用条件表达式求三个数的最大值 测试int,float,char类型在本机所占的字节数 单个字符的输入getchar() 使用*抑制符跳过输入 ...

  9. AutoCAD学习之基本操作学习笔记

    AutoCAD学习 基本操作(23.2.15~23.2.17) Ctrl+N 新建一个CAD文档 F7 删除格栅 F3 对象捕捉(很重要啊,如果一直开着,操作起来很费劲.),需要关掉,注意使用snip ...

  10. linux学习(一)——基本操作(权限、路径、文件、压缩)

    文章目录 基本操作 用户权限 文件相关操作 搜索文件 压缩解压 磁盘管理 帮助命令 基本操作 tab:补全命令 alt+Backspace:向前删除一个单词 通配符: * 使用 touch 命令创建 ...

最新文章

  1. vim 插件_你不得不知道的适用于程序员的VIM插件
  2. 代码小结:时区的时间问题
  3. linux 单用户密码修改
  4. 用matlab画玫瑰代码,网上收到的用matlab画玫瑰花的代码怎么不行啊,报告错误,求大神...
  5. php无重复字符的最长子串,无重复字符的最长字串问题
  6. 如何写好标题,才能轻松上简书首页?
  7. 记TensorFlow项目开源一周年
  8. linux ipc 信号量,linux ipc信号量
  9. 知识图谱构建流程与实现技术浅谈
  10. oracle 实现自增序列
  11. python加粗线宽代码_python-在matplotlib中同时更改线宽和颜色
  12. windows“运行”自定义“命令”的实现
  13. 地信实验一利用矢量化软件AutoCAD对栅格文件矢量化
  14. Home Assistant 发现小米设备
  15. Grad-CAM论文总结
  16. Linux命令:ifconfig出现command not found 的解决办法
  17. X电容(差模电容)和Y电容(共模电容)简介
  18. 联想7400打印机如何与手机连到一起_联想打印机力度空前的眼红优惠来袭 这波福利可不能再错过了...
  19. WireShark 安装及简单使用
  20. 美国州名英文,介绍美国各州名缩写,50个州名简写和简称及其首府名

热门文章

  1. 基于Java毕业设计/疫情展示平台源码+系统+mysql+lw文档+部署软件
  2. 卸载华为系统wifi服务器,如何安装随行WiFi驱动及如何卸载驱动
  3. HTML九宫格拼图游戏代码,js实现九宫格拼图小游戏
  4. java 换行规范_Java代码规范
  5. Java中判断String不为空的问题性能比较
  6. nmap和masscan
  7. Java中常用到的英语单词读音以及解释
  8. linux中 zip命令将整个目录打成zip包
  9. Python内置函数一览表
  10. centos7安装bbr_Centos7下,BBR修正版 一键安装与使用