Springboot笔记<13>单元测试
单元测试
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库,使用@SpringBootTest
注解会以springboot的环境启动
JUnit5常用注解
@Test :表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
@ParameterizedTest :表示方法是参数化测试
@RepeatedTest :表示方法可重复执行
@DisplayName :为测试类或者测试方法设置展示名称
@BeforeEach :表示在每个单元测试之前执行
@AfterEach :表示在每个单元测试之后执行
@BeforeAll :表示在所有单元测试之前执行
@AfterAll :表示在所有单元测试之后执行
@Tag :表示单元测试类别,类似于JUnit4中的@Categories
@Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith :为测试类或测试方法提供扩展类引用
断言(assertions)
断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。JUnit 5 内置的断言可以分成如下几个类别:
1、简单断言
用来对单个值进行简单的验证。如:
assertEquals | 判断两个对象或两个原始类型是否相等 |
---|---|
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象引用是否指向同一个对象 |
assertNotSame | 判断两个对象引用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象引用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
@Test
@DisplayName("simple assertion")
public void simple() {
assertEquals(3, 1 + 2, "simple math");
assertNotEquals(3, 1 + 1);
assertNotSame(new Object(), new Object());
Object obj = new Object();
assertSame(obj, obj);
assertFalse(1 > 2);
assertTrue(1 < 2);
assertNull(null);
assertNotNull(new Object());
}
2、数组断言
通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等
@Test
@DisplayName("array assertion")
public void array() {
assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
3、组合断言
assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言
@Test
@DisplayName("assert all")
public void all() {
assertAll("Math",
() -> assertEquals(2, 1 + 1),
() -> assertTrue(1 > 0)
);
}
4、异常断言
在JUnit4时期,想要测试方法的异常情况时,需要用@Rule注解的ExpectedException变量还是比较麻烦的。而JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用。
@Test
@DisplayName("异常测试")
public void exceptionTest() {
ArithmeticException exception = Assertions.assertThrows(
//扔出断言异常
ArithmeticException.class, () -> System.out.println(1 % 0));
}
5、超时断言
Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间
@Test
@DisplayName("超时测试")
public void timeoutTest() {
//如果测试方法时间超过1s将会异常
Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
6、快速失败
通过 fail 方法直接使得测试失败
@Test
@DisplayName("fail")
public void shouldFail() {
fail("This should fail");
}
前置条件(assumptions)
JUnit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。Assumptions和Assertions容易混淆,因此这里通过对比它们来学习:
- Assertions即断言类,里面提供了很多静态方法,例如assertTrue,如果assertTrue的入参为false,就会抛出AssertionFailedError异常,Junit对抛出此异常的方法判定为失败;
- Assumptions即假设类,里面提供了很多静态方法,例如assumeTrue,如果assumeTrue的入参为false,就会抛出TestAbortedException异常,Junit对抛出此异常的方法判定为跳过;
- 简单的说,Assertions的方法抛出异常意味着测试不通过,Assumptions的方法抛出异常意味着测试被跳过;
@DisplayName("前置条件")
public class AssumptionsTest {
private final String environment = "DEV";
@Test
@DisplayName("simple")
public void simpleAssume() {
assumeTrue(Objects.equals(this.environment, "DEV"));
assumeFalse(() -> Objects.equals(this.environment, "PROD"));
}
@Test
@DisplayName("assume then do")
public void assumeThenDo() {
assumingThat(
Objects.equals(this.environment, "DEV"),
() -> System.out.println("In DEV")
);
}
}
1.assumeTrue可以接受Supplier类型作为第二个入参,如果assumeTrue失败就会将第二个参数的内容作为失败提示:
2.assumingThat方法,可以接受Executable类型作为第二个入参,如果第一个入参为true就会执行Executable的execute方法,注意assumingThat方法的特点:不抛出异常,因此其所在的方法不会被跳过,这是和assumeTrue相比最大的区别(assumeTrue一旦入参为false就会抛出异常,其所在方法就被标记为跳过)
嵌套测试
JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
参数化测试
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用@ValueSource等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。让我真正感到他的强大之处的地方在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现ArgumentsProvider接口,任何外部文件都可以作为它的入参。
@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) {
System.out.println(string);
Assertions.assertTrue(StringUtils.isNotBlank(string));
}
@ParameterizedTest
@MethodSource("method") //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
Assertions.assertNotNull(name);
}
static Stream<String> method() {
return Stream.of("apple", "banana");
}
Springboot笔记<13>单元测试的更多相关文章
- SpringBoot学习笔记:单元测试
SpringBoot学习笔记:单元测试 单元测试 单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作.程序单元是应用的最小可测试部 ...
- 机器学习实战 - 读书笔记(13) - 利用PCA来简化数据
前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第13章 - 利用PCA来简化数据. 这里介绍,机器学习中的降维技术,可简化样品数据. ...
- Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法
Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法 这篇笔记将介绍如何使用Ext.Net GridPanel 中使用Sorter. 默认情况下,Ext.Net GridP ...
- 读书笔记-实用单元测试(英文版) Pragmatic Unit Testing in C# with NUnit
读书笔记-实用单元测试(英文版) Pragmatic Unit Testing in C# with NUnit Author: Andrew Hunt ,David Thomas with Matt ...
- SQL反模式学习笔记13 使用索引
目标:优化性能 改善性能最好的技术就是在数据库中合理地使用索引. 索引也是数据结构,它能使数据库将指定列中的某个值快速定位在相应的行. 反模式:无规划的使用索引 1.不使用索引或索引不足 2.使用了 ...
- JAVA自学笔记13
JAVA自学笔记13 1.StringBuffer类 1)线程安全的可变字符序列 线程安全(即同步) 2)StringBuffer与String的区别:一个可变一个不可变 3)构造方法: ①publi ...
- golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换
golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...
- springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定
springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 标签: springmvc springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需 ...
- 强化学习读书笔记 - 13 - 策略梯度方法(Policy Gradient Methods)
强化学习读书笔记 - 13 - 策略梯度方法(Policy Gradient Methods) 学习笔记: Reinforcement Learning: An Introduction, Richa ...
- Python3+Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)'''from sel ...
随机推荐
- [tldr] 如何给自己的程序编写一个systemd服务
参考Systemd 入门教程:实战篇 配置文件 systemd使用配置文件作为程序服务启动的方式,分为可以自启动的和不能自启动的 就是enable和start的命令的区别 分为/etc/systemd ...
- 报错:ReferenceError: __dirname is not defined in ES module scope
报错: __dirname is not defined in ES module scope 前言 新版 NodeJS 支持通过 ESM 方式导入模块,代码如: // CommonJS 规范(旧) ...
- k8s Error: failed to prepare subPath for volumeMount "custom-logo" of container "grafana"
前言 使用 k8s 挂载卷文件时,使用了 hostPath,type: File volumeMounts: - mountPath: /usr/share/grafana/public/img/gr ...
- vue学习一(指令3.v-on,v-for)
3.1.v-on 绑定事件 可以简写为@ ,按键修饰符 v-on:keyup = @keyup 事件修饰符:v-on提供了事件修饰符 修饰符是由点开头的指令后缀来表示的 ...
- maven为什么发生依赖冲突?怎么解决依赖冲突?
maven为什么发生依赖冲突?怎么解决依赖冲突? 我们在开发的时候,偶尔会遇到依赖冲突的时候,一般都是NoClassDefFoundError.ClassNotFoundException.NoSuc ...
- 堆排序(topk 问题)(NB)
博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ # 比较排序 import random def sift(li, low, h ...
- Oracle体系结构和用户管理
本篇博客将对Oracle的体系结构.存储结构.内存结构和进程结构进行初步介绍,从而从宏观上把握它的物理组成.文件组成和各种进程,对于进一步的了解可以起到很好地作用 一.Oralce体系结构 1.概述 ...
- centos7 下全局配置最新版的golang语言开发环境
按照以下步骤进行操作: 前往Go官方网站下载页面(https://golang.org/dl/)查找最新版本的Go二进制文件. 使用wget命令下载最新版本的Go二进制文件.例如,如果最新版本是1.1 ...
- 内部类--匿名内部类--java进阶day03
1.匿名内部类 在介绍匿名内部类前,先引用一段代码材料,通过这段代码来理解匿名内部类 如下图,我们定义了接口和一个方法,方法中调用该接口的抽象方法,这时我们要调用use方法,但是该怎么传参呢? 我们将 ...
- frxpngimage单元的编译错误:frxpngimage left side cannot be assigned to
一个老项目中,使用软数字录入数据,编译时出现n个:frxpngimage left side cannot be assigned to 原因是使用了frxpngimage单元,在D11中编译出现若干 ...