spring boot 单元测试JUnit5使用断言Assertions和假定Assumptions、嵌套、参数测试

news/2024/10/30 14:14:42/

spring boot 单元测试JUnit5使用断言Assertions和假定Assumptions、嵌套、参数测试

本文基于spirng boot 2.7.11, 大家注意自己的版本

Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库

SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖

源码地址:https://gitcode.net/qq_39339588/springboot.git

文章目录

      • spring boot 单元测试JUnit5使用断言Assertions和假定Assumptions、嵌套、参数测试
        • 1. 标记单元测试类和方法
        • 2. 断言的简单使用
          • 1)基本类型和对象的断言
          • 2)数组断言
          • 3)组合断言
          • 4)异常断言
          • 5)超时断言
          • 6)快速失败断言
        • 3. 前置条件断言,假设假定
        • 4. 嵌套@Nested
        • 5. 参数化测试
          • 1)@ValueSource注解,基本类型入参
          • 2)@NullSource注解,null入参
          • 3)@EnumSource注解,枚举入参
          • 4)@CsvSource注解,多参数入参
          • 5)@CsvFileSource,参数文件入参
          • 6)@MethodSource注解,方法返回值入参
          • 7) @ArgumentsSource注解,自定义参数入参

1. 标记单元测试类和方法

@SpringBootTest注解,可以标记为测试类

@Test注解标记是测试方法

@DisplayName注解是标记个名称

@SpringBootTest
public class HelloWorldTest {/*** 断言基础*/@Test@DisplayName("简单断言")public void simple() {}
}

2. 断言的简单使用

1)基本类型和对象的断言
/**
* 基本类型和对象的断言
*/
@Test
@DisplayName("简单断言")
public void simple() {Assertions.assertEquals(3, 1 + 2, "不相等");Assertions.assertNotEquals(3, 1 + 1, "相等了");//断言对象Assertions.assertNotSame(new Object(), new Object(), "对象相同");Object o = new Object();Assertions.assertSame(o, o, "断言不相等了");Assertions.assertFalse(1 > 2);Assertions.assertTrue(1 < 2);Assertions.assertNull(null);Assertions.assertNotNull(new Object());
}
2)数组断言
@DisplayName("数组断言")
@Test
public void array() {// 断言两个数组对象不相等Assertions.assertNotEquals(new int[]{1, 2}, new int[]{1, 2});
}
3)组合断言
@DisplayName("组合断言")
@Test
public void all() {// 断言所多个断言方法都正确Assertions.assertAll("组合断言",() -> Assertions.assertEquals(2, 1 + 1),() -> Assertions.assertTrue(1 > 0));
}
4)异常断言
@DisplayName("异常断言")
@Test
public void exception() {// 断言方法 会出现异常ArithmeticException arithmeticException = Assertions.assertThrows(ArithmeticException.class, () -> System.out.println(1 % 0));arithmeticException.printStackTrace();
}
5)超时断言
@DisplayName("超时断言")
@Test
public void timeOut() {// 断言方法执行不会超过1秒Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
6)快速失败断言
@DisplayName("快速失败")
@Test
public void failFast() {// 触发快速失败后AssertionFailedError ex = Assertions.assertThrows(AssertionFailedError.class, () -> {Assertions.fail("触发快速失败");});ex.printStackTrace();
}

3. 前置条件断言,假设假定

执行断言的前提条件,如果假定成功true,才会去执行

/*** 前置条件,假设假定*/
@DisplayName("前置条件")
@Test
public void assuming() {String evn = "dev";// 执行断言的前提条件,如果假定成功true,才会去执行下一行,如果假定失败,下边的就不执行了Assumptions.assumeTrue(Objects.equals(evn, "dev"));Assumptions.assumeFalse(Objects.equals(evn, "prod"));System.out.println("dev和不是prod,执行了");Assumptions.assumeTrue(Objects.equals(evn, "dev1"));System.out.println("dev1,这句会忽略,不会执行输出");
}/*** 假定成功true,才会去执行 执行器方法*/
@DisplayName("前置条件That")
@Test
public void assumingThat() {// 假定成功,才会去执行 执行器方法Assumptions.assumingThat(Objects.equals("dev", "dev"), () -> {System.out.println("in dev");});
}

4. 嵌套@Nested

内部嵌套,每次会先走外层的beforeEach,在走内部的beforeEach;支持嵌套的嵌套

@DisplayName("单元测试示例")
@SpringBootTest
public class HelloWorldTest {Stack<Object> stack;/*** 内部嵌套,每次会先走外层的beforeEach,在走内部的beforeEach*/@DisplayName("内部嵌套测试")@Nestedclass InnerTest {@BeforeEachvoid newStack() {// 创建一个栈对象stack = new Stack<>();}@DisplayName("检查是否为空")@Testvoid isEmpty() {Assertions.assertTrue(stack.isEmpty());}@DisplayName("抛出一个栈pop异常")@Testvoid throwExceptionWhenPop() {Assertions.assertThrows(EmptyStackException.class, stack::pop);}@DisplayName("抛出一个栈peek异常")@Testvoid throwExceptionWhenPeek() {Assertions.assertThrows(EmptyStackException.class, stack::peek);}@Nested@DisplayName("内部的内部嵌套测试")class InnerInnerTest {String item = "item";@BeforeEachvoid pushAnItem() {// 放入一个元素stack.push(item);}@DisplayName("不为空了")@Testvoid isNotEmpty() {Assertions.assertFalse(stack.isEmpty());}@DisplayName("取出一个来,用pop")@Testvoid returnItemByPop() {Assertions.assertEquals(item, stack.pop());Assertions.assertTrue(stack.isEmpty());}@DisplayName("取出一个来,用peek")@Testvoid returnItemByPeek() {Assertions.assertEquals(item, stack.peek());Assertions.assertFalse(stack.isEmpty());}}}

5. 参数化测试

参数化测试,让单元测试的方法支持接收传入的参数

将可以使用不同的参数进行多次单元测试,有多少套参数,就执行多少次单元测试

而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码

1)@ValueSource注解,基本类型入参
/*** @ValueSource:为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型* @param params*/
@DisplayName("参数化测试,值来源")
@ParameterizedTest
@ValueSource(strings = {"a", "b", "c"})
public void parameterizedTest(String params) {// 会执行3次,分别执行a,b,cSystem.out.println(params);Assertions.assertTrue(StringUtils.isNotBlank(params));
}
2)@NullSource注解,null入参
/*** null入参** @param params*/
@DisplayName("null的入参")
@ParameterizedTest
@NullSource
public void testNull(String params) {Assertions.assertNull(params);
}
3)@EnumSource注解,枚举入参
/*** 枚举入参,会把枚举遍历一遍,分别执行一次方法*/
@DisplayName("枚举的入参")
@ParameterizedTest
@EnumSource(TestEnum.class)
public void testEnumSource(TestEnum params) {System.out.println("state:" + params.state + ",msg:" + params.msg);// state:1,msg:好// state:2,msg:不好Assertions.assertNotNull(params);
}/*** 枚举类*/
@Getter
@AllArgsConstructor
public enum TestEnum {GOOD(1, "好"),BAD(2, "不好");int state;String msg;
}
4)@CsvSource注解,多参数入参
@DisplayName("参数化测试,@CsvSource")
@ParameterizedTest
@CsvSource({"a,b,c"})
void parameterizedTestCsvSource(String a, String b, String c) {// 默认使用逗号分隔System.out.println(a + b + c);Assertions.assertNotNull(a);
}@DisplayName("参数化测试,@CsvSource2")
@ParameterizedTest
@CsvSource(value = {"a,b,c-D"}, delimiterString = "-")
void parameterizedTestCsvSource2(String abc, String d) {// 默认使用逗号分隔,指定分隔符"-"System.out.println(abc);System.out.println(d);Assertions.assertNotNull(abc);// a,b,c// D
}
5)@CsvFileSource,参数文件入参

可以把文件中的内容当做参数,批量来执行,下边附带了my.csv和my2.csv文件内容

注意,要在测试目录下,新建resources目录,再放入my.csv和my2.csv文件

/*** 参数文件** @param methodName*/
@DisplayName("参数化测试,@CsvFileSource")
@ParameterizedTest
@CsvFileSource(resources = "/my.csv")
void parameterizedTestWithCsvFileSource(String methodName) {// 测试目录下,新建resources目录System.out.println(methodName);Assertions.assertNotNull(methodName);
}@DisplayName("参数化测试,@CsvFileSource")
@ParameterizedTest
@CsvFileSource(resources = "/my2.csv", delimiterString = "|")
void parameterizedTestWithCsvFileSource2(String name, Integer age) {// 测试目录下,新建resources目录System.out.println(name + ":" + age);Assertions.assertNotNull(name);// a:18// b:17// c:20
}

my.csv文件

1
2
3
4

my2.csv

a|18
b|17
c|20
6)@MethodSource注解,方法返回值入参

把一个方法的返回值,作为测试用例方法的参数

/*** 动态参数*/
@DisplayName("参数化测试,方法来源")
@ParameterizedTest
@MethodSource("method1") // 如果不指定方法名称,会去找与自己相同名称的静态方法
public void parameterizedTestWithMethodParam(String params) {// MethodSource("method1") 接收这个方法的返回值,之后会执行2次,a,bSystem.out.println(params);Assertions.assertNotNull(params);
}static Stream<String> method1() {return Stream.of("a", "b");
}@DisplayName("参数化测试,方法来源,多参数")
@ParameterizedTest
@MethodSource // 如果不指定方法名称,会去找相同名称的静态方法
public void parameterizedTestWithMethodMultipleParams(String name, Integer age) {System.out.println(name + ":" + age);// a:18// b:17// c:20Assertions.assertNotNull(name);
}static Stream<Arguments> parameterizedTestWithMethodMultipleParams() {return Stream.of(Arguments.arguments("a", 18),Arguments.arguments("b", 17),Arguments.arguments("c", 20));
}
7) @ArgumentsSource注解,自定义参数入参
/*** 实现ArgumentsProvider接口,并在测试方法上使用@ArgumentsSource注解。*/
@DisplayName("@ArgumentsSource注解")
@ParameterizedTest
@ArgumentsSource(MyArgumentsProvider.class)
public void testArgumentsSource(String name, int age) {System.out.println(name + ":" + age);// aa:18// bb:20// cc:30Assertions.assertNotNull(name);
}

http://www.ppmy.cn/news/107908.html

相关文章

知识变现海哥:知识变现从入门到实操,缺的不是知识,而是知识变现的能力。

知识只能改变学历&#xff0c;知识变现才能改变命运。通过研究知识变现的路径&#xff0c;无论市文案工作者还是声音工作者我们能看到的微信生态圈&#xff0c;抖音类视频生态&#xff0c;百度等搜索系生态圈&#xff0c;喜马拉雅FW&#xff0c;荔枝等音频生态都是很好的知识变…

如何在 Alpine Linux 上启用或禁用防火墙?

防火墙是计算机网络安全的重要组成部分&#xff0c;它用于保护计算机和网络免受未经授权的访问和恶意攻击。Alpine Linux 是一种轻量级的 Linux 发行版&#xff0c;常用于构建容器化应用和嵌入式系统。本文将详细介绍如何在 Alpine Linux 上启用或禁用防火墙。步骤 1&#xff1…

Qt(C++)使用QChart静态显示3个设备的温度变化曲线

一、QChart介绍 QChart模块是Qt Charts库的基础,提供了用于创建和显示各种类型图表的类和接口。Qt Charts库是一个功能丰富、易于使用的数据可视化工具库,可以帮助开发者在应用程序中添加漂亮而又交互性强的图表。 QChart模块主要包括以下类: QChart:表示一个基本的图表容…

RocketMQ 多级存储设计与实现

作者&#xff1a;张森泽 随着 RocketMQ 5.1.0 的正式发布&#xff0c;多级存储作为 RocketMQ 一个新的独立模块到达了 Technical Preview 里程碑&#xff1a;允许用户将消息从本地磁盘卸载到其他更便宜的存储介质&#xff0c;可以用较低的成本延长消息保留时间。本文详细介绍 …

ORA-01555

ORA-01555 rollback records needed by a reader for consistent read are overwritten by other writers 回滚数据时被其他事务覆写 从应用角度来看ORA-015551.查询执行时间太长。首先是优化查询&#xff0c;然后考虑在数据块不繁忙的时候运行&#xff0c;最后考虑加大回滚段…

voc xml 转 coco json

# -*- coding: utf-8 -*- # !/usr/bin/env pythonimport os import json from tqdm import tqdm from imutils import paths import xml.etree.ElementTree as ETdef xml2coco(name_id, xml_dir, json_file):# COCO JSON 文件的初始化数据结构coco_dict {"images": …

畅游星河的炫彩手柄,配置也不简单,北通阿修罗2Pro上手

平时在PC上玩个游戏&#xff0c;还是手柄更好用。在国产的手柄里面&#xff0c;北通的很多人都用&#xff0c;选择比较多&#xff0c;价格相对也更加亲民一些&#xff0c;之前看到北通阿修罗2Pro新出了一款无线星河版本&#xff0c;做得很好看&#xff0c;上周到手后试了试&…

应急启动电源充气泵方案芯片

应急启动电源充气泵方案是一个将汽车应急启动电源和充气泵相结合的方案设计&#xff0c;并且在开发时做简化设计&#xff0c;使其成为可便携、带有户外LED照明及监测车胎、多种模式充气的电子产品。今天我们就来聊一聊关于这个电子产品的方案设计。 应急启动电源充气泵方案在开…