Spring 官方建议的在 Spring Boot 应用中如何做单元测试

news2024/11/20 15:15:45

Spring Boot 提供了丰富的测试功能,主要由以下两个模块组成:

● spring-boot-test:提供测试核心功能。

● spring-boot-test-autoconfigure:提供对测试的自动配置。

Spring Boot 提供了一个 spring-boot-starter-test一站式启动器,如以下依赖配置所示。

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
</dependency>

测试启动器依赖不仅包含以上两个 Spring Boot模块,还包含 Spring Test 测试模块,以及其他

第三方测试类库,如下所示。

● JUnit 5:Java 最主流的单元测试框架。

● AssertJ:一款快速断言库。

● Hamcrest:一款单元测试匹配库。

● Mockito:一款 Mock 测试框架。

● JSONassert:一款 JSON 断言库。

● JsonPath:一款 JSON XPath 库。

更多测试相关的依赖可见具体的依赖关系树,如下图所示。

图片

以上这些都是 Spring Boot 提供的常用的测试类库,如果上面的测试类库还不能满足你的需要,也可以任意添加以上没有的类库。

现在基本上使用的是 JUnit 5,如果应用还在使用JUnit 4 写的单元测试用例,那么也可以使用JUnit 5 的 Vintage 引擎来运行,如下面的依赖配置所示。

<dependency>
 <groupId>org.junit.vintage</groupId>
 <artifactId>junit-vintage-engine</artifactId>
 <scope>test</scope>
 <exclusions>
     <exclusion>
         <groupId>org.hamcrest</groupId>
         <artifactId>hamcrest-core</artifactId>
     </exclusion>
 </exclusions>
</dependency>

需要排除 hamcrest-core 依赖,因为该依赖已经改坐标了,并且默认内置在Spring Boot依赖管理中,如上面的依赖关系树所示,最新的 Hamcrest依赖已经是org.hamcrest:hamcrest坐标了。

Spring Boot提供了一个 @SpringBootTest 注解,用在单元测试类上以启用支持Spring Boot特性的单元测试,如果使用的是JUnit 4,那么测试类上还需要额外的@RunWith(SpringRunner. class)注解,然后在测试类方法上添加 @Test 注解即可,每一个 @Test 注解修饰的方法就是一个单元测试方法。

@SpringBootTest 注解有一个最重要的 webEnvironment 环境参数,支持以下几种环境设置:

●MOCK(默认):加载一个 Web ApplicationContext 并提供一个 Mock Web Environment,但不会启动内嵌的 Web 服务器,并可以结合 @AutoConfifigureMockMvcor 和 @AutoConfifigure-WebTestClient 注解一起使用进行 Mock 测试。

● RANDOM_PORT:加载一个 WebServerApplicationContext,以及提供一个真实的 WebEnvironment,并以随机端口启动内嵌服务器。

●DEFINED_PORT:和 RANDOM_PORT 一样,不同的是 DEFINED_PORT 是以应用指定的端口运行的,默认端口为 8080。

●NONE:加载一个 ApplicationContext,但不会提供任何 Web Environment。

如果使用的 @SpringBootTest 注解不带任何参数,则默认为 Mock 环境。

真实环境测试

在 @SpringBootTest 注解中指定基于随机端口的真实Web环境,然后在类成员变量或者方法参数上注入 TestRestTemplate 实例,就可以完成对 Spring MVC接口的真实环境测试。

下面是一个基于随机端口的真实环境的测试用例:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MvcTest {
 @Test
 public void getUserTest(@Autowired TestRestTemplate testRestTemplate) {
 Map<String, String> multiValueMap = new HashMap<>();
 multiValueMap.put("username", "Java 技术栈 ");
 Result result = testRestTemplate.getForObject("/user/get?username={username}",
 Result.class, multiValueMap);
 assertThat(result.getCode()).isEqualTo(0);
 assertThat(result.getMsg()).isEqualTo("ok");
 }
 
}

测试当前应用下的 /user/get 接口,传入对应的用户名参数,最后检查接口返回结果是否和预期一致,测试结果如下图所示。

图片

单元测试通过,从执行日志可以看到,它启动了一个嵌入式的 Tomcat 容器来测试真实的 Web应用环境。

Mock 环境测试

通过在类上面使用 @AutoConfifigureMockMvc 注解,然后在类成员变量或者方法参数上注入MockMvc 实例,就可以完成对 Spring MVC 接口的 Mock 测试。

下面是一个基于默认 Mock 环境的测试用例:

@SpringBootTest
@AutoConfigureMockMvc
class MockMvcTests {
 @Test
 public void getUserTest(@Autowired MockMvc mvc) throws Exception {
 mvc.perform(MockMvcRequestBuilders.get("/user/get?username={username}", "test"))
 .andExpect(status().isOk())
 .andExpect(content().string("{\"code\":0,\"msg\":\"ok\",\"
data\":\"test\"}"));
 }
}

测试当前应用下的 /user/get 接口,传入对应的用户名参数,最后检查请求状态是否OK(200),响应的内容是否和预期一致,测试结果如下图所示。

图片

单元测试通过,从执行日志可以看到,它并未启动真实的 Web 环境来测试,而是使用 Mock 环境测试的。

Mock 组件测试

某些时候可能还需要模拟一些组件,比如某些服务只有上线之后才能调用,在开发阶段不可用,这时就需要 Mock 模拟测试了,提供各种模拟组件以完成测试。

Spring Boot 提供了一个 @MockBean 注解,可为 Spring 中的 Bean 组件定义基于 Mockito 的Mock 测试,它可以创建一个新 Bean 以覆盖 Spring 环境中已有的 Bean,它可以用在测试类、成员变量上,或者 @Confifiguration 配置类、成员变量上,被模拟的 Bean 在每次测试结束后自动重置。

假现现在有一个远程的服务 userService,本地不能调用,现在进行 Mock 测试,如以下使用示例所示。

@SpringBootTest
class MockBeanTests {
// @Autowired
// private UserService userService;
 @MockBean
 private UserService userService;
 @Test
 public void countAllUsers() {
 BDDMockito.given(this.userService.countAllUsers()).willReturn(88);
 assertThat(this.userService.countAllUsers()).isEqualTo(88);
 }
}

这里的 @MockBean 注解使用在 UserService 变量上,表明这个userService实例在当前测试用例中是被 Mock 覆盖的,如果要模拟的 Bean 有多个,则可以使用@Qualififier注解指定,然后通过Mockito 提供的代理工具类方法创建模拟返回数据,运行该服务的测试方法,当模拟数据和预期结果一致时才会测试通过。

这里通过 BDDMockito 工具类模拟 userService#countAllUsers方法并让它返回统计的用户总数(88),最后检查该方法的返回值是否和预期一致,测试结果如下图所示。

图片

单元测试通过,也可以使用 @SpyBean 注解代替 @MockBean 注解,两者的区别是:

● @SpyBean—如果没有提供 Mockito 代理方法,则会调用真实的 Bean 来获取数据。

● @MockBean—不管有没有提供 Mockito 代理方法,都会调用 Mock 的 Bean 来获取数据。

@MockBean、@SpyBean 注解既可作用于 Mock 环境,也可作用于真实环境,它只是用来模拟、替换环境中指定的 Bean 而已,但不能用于模拟在应用上下文刷新期间 Bean 的行为,因为在执行测试用例时应用上下文已经刷新完成了,所以不可能再去模拟了,这种情况下建议使用 @Bean 方法来创建模拟配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/553684.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot+vue私人健身与教练预约管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的私人健身与教练预约管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&…

【Java】常见内存溢出OOM

文章目录 前言一、定义二、 为什么会OOM&#xff1f;三、JVM内存模型四、OOM常见类型4.1 java堆内存溢出4.2 方法区溢出4.3 JAVA虚拟机栈溢出 五、OOM分析--heapdump总结 前言 一、定义 内存溢出&#xff1a; out of memory&#xff0c;OOM&#xff0c;全称“Out Of Memory”&…

西门子S7-1200 PLC之间无线PROFINET通信

西门子S7-1200 PLC 使用Profinet通讯时&#xff0c;一个做Profinet IO控制器&#xff0c;一个做Profinet IO设备。一个Profinet IO控制器可以最多支持16个Profinet IO设备&#xff0c;Profinet通讯不使用通讯指令&#xff0c;只需要配置好数据传输地址&#xff0c;就能够实现数…

睿铂在广东,自然资源部经济管理科学研究所“多测合一”项目分享

引言 DG4 Pros倾斜摄影相机作为睿铂旗舰系列产品&#xff0c;它的硬件与软件配置都无愧于其顶级倾斜相机的称号。在它的帮助下&#xff0c;客户得以挑战很多以往受限于设备技术条件&#xff0c;实施起来非常困难的项目。 本次&#xff0c;自然资源部经济管理科学研究所&#…

App Store上线APP流程

现在App Store上已经有数百万款应用&#xff0c;因此对于App的规范要求也越来越高&#xff0c;对于新上线的APP需要满足这些规则并不是件容易的事。今天和大家分享这方面的知识&#xff0c;希望大家喜欢。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff…

Mysql中存储引擎的区别及比较

MyISAM存储引擎 MyISAM基于ISAM存储引擎&#xff0c;并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度&#xff0c;但不支持事务。 MyISAM主要特性有&#xff1a; 1、大文件&#xff08;达到63位文件长度&#…

AI人工智能随机森林分类器的原理、优缺点、应用场景和实现方法

随机森林分类器&#xff08;Random Forest Classifier&#xff09;是一种常用的机器学习算法&#xff0c;它是基于决策树的一种集成学习方法。在人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;领域中&#xff0c;随机森林分类器是一种高效的算法&…

艺术签名免费设计的方法分享,快来收下

在今天的数字时代&#xff0c;艺术签名已经成为一个流行的趋势。无论是在社交媒体上&#xff0c;还是在个人品牌推广中&#xff0c;艺术签名都是一个重要的元素。但是&#xff0c;对于很多人来说&#xff0c;设计一个独特的艺术签名可能需要付出昂贵的代价。然而&#xff0c;有…

flstudio21更新内容介绍FL水果2023旗舰版下载

昨天为大家展示了 FL STUDIO21 新增的插件&#xff0c;今天让我们看一看还有哪些新变化&#xff1f;FL Studio中文版惯称水果, 是一个完整的电音软件音乐制作环境或数字音频工作站。是现在流行的数字音频工作站之一,包括撰写,整理,记录,编辑,电音,混音和掌握专业品质的音乐。 0…

Open Ai 常见接口参数说明以及常见报错总结

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

【SPSS】生存-寿命表分析详细操作教程(附案例实战)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Plc能否通过以太网网关实现无线数据交互?

西门子S7-1200 PLC 使用Profinet通讯时&#xff0c;一个做Profinet IO控制器&#xff0c;一个做Profinet IO设备。一个Profinet IO控制器可以最多支持16个Profinet IO设备&#xff0c;Profinet通讯不使用通讯指令&#xff0c;只需要配置好数据传输地址&#xff0c;就能够实现数…

Cesium 实战 - 模型亮度调整(解决模型非常暗的问题)

Cesium 实战 - 模型亮度调整&#xff08;解决模型非常暗的问题&#xff09; 环境版本试错过程解决问题在线示例 在某个项目中&#xff0c;遇到个问题&#xff0c;模型加载之后非常暗&#xff0c;经其他软件确认&#xff0c;模型本身正常&#xff0c;但是通过 Cesium 加载之后就…

Vue3项目技巧(更新中ing)

文章目录 axios封装http.jstestAPI.jsmain.js测试如果项目中需要多个baseURL 自动导入scss文件案例文件使用案例 引入aliyun图标库先看效果查看官网文档引入并使用 vueuse实现-吸附导航交互安装案例 多个组件共享的请求、数据、封装到pinia案例父组件中调用子组件中应用 axios封…

django admin后台管理系统中配置可上传多张图片功能

目录 一、默认的常规方式只能上传一张图片的示例 二、配置可上传多张图片 问题&#xff1a;在django自带的admin后台管理系统中常规的方式只能上传一张图片&#xff0c;无法上传添加多张图片&#xff0c;如下图。所以现在需要配置可上传多张图片的功能&#xff01; 一、默认的…

【Atlas200】Host?Device?RC?EP?

目录 atlas500的ep模式Atlas 200 DK的host侧内存地址的分配Device侧内存管理内存的拷贝复用方案atlas500的ep模式 如上图所示,cpu+内存一侧为host侧;而gpu+显存一侧为device侧。 Atlas 200 DK的 在昇腾310AI处理器(NPU)中,Davinci Core负责专用计算,而Control CPU则负责…

拉电流 、灌电流、吸收电流

单片机的引脚&#xff0c;可以用程序来控制&#xff0c;输出高、低电平&#xff0c;这些可算是单片机的输出电压。但是程序控制不了单片机的输出电流。单片机的输出电流&#xff0c;很大程度上是取决于引脚上的外接器件。 什么是拉电流 、灌电流、吸收电流 ? 51单片机的IO口驱…

SpringCloud(28. 分布式会话与分布式事务)

上一篇&#xff1a;27. Redis 和 ZK 分布式锁 文章目录 1. 集群部署时的分布式 session 如何实现&#xff1f;2. 分布式事务方案2.1 两阶段提交方案/XA方案2.2 TCC 方案2.3 本地消息表2.4 可靠消息最终一致性方案2.5 最大努力通知方案 1. 集群部署时的分布式 session 如何实现&…

极狐(GitLab) 重磅发布新产品「极狐星」,让研发效能看得清,算得准,成就企业精英效能管理

在研发驱动业务增长的今天&#xff0c;越来越多的研发管理者发现&#xff1a; 总是觉得研发资源不够用&#xff1f; 如何用数据衡量研发效能&#xff1f; 如何定位软件交付瓶颈&#xff1f; 怎样管理并预警项目状态&#xff1f; 想尽早发现代码泄露风险怎么办&#xff1f;…