学透Spring Boot — 010. 单元测试和Spring Test

系列文章目录

这是CSDN postnull 博客《学透Spring Boot》系列的一篇,更多文章请移步:Postnull - 学透Spring Boot系列文章


文章目录

  • 系列文章目录
  • 前言
  • 1. 基本概念
    • UT 单元测试
    • TDD 测试驱动开发
    • UT测试框架
    • Mock框架
  • 3. Spring Test
    • 为什么要用Spring Test
    • 引入Spring Test
    • Spring Test最简单使用


前言

开发的过程中,写业务代码是工作的一部分,测试也是工作的一部分。尤其是作为开发人员,用单元测试来测试我们的代码,可以更早的发现bug。

1. 基本概念

UT 单元测试

单元测试 Unit Testing,通常是开发的一部分,也是开发过程中最小的测试单元。主要测试一个类或一个方法的逻辑。

因为只是保证我们自己写的代码的逻辑,所以是不涉及外部服务的(比如数据库和外部接口),外部服务我们通常使用mock来模拟它们的行为。

UT是代码片段的测试
外部集成测试才需要依赖真正的外部服务

TDD 测试驱动开发

近些年流行很多种 XDD,其中和测试相关的就是TDD,Test driven development,这是一种开发方法。

以前传统的开发模式,我们先一口气写完业务代码,然后再开始写单元测试。但是会遇到一些问题:

  • 业务代码不方便测试
  • 测试时才发现bug,导致业务代码要做很大的调整

所以我们可以换一种思路,先写测试用例,再写业务代码。
这也就是TDD的三个步骤,遵循 红-绿-重构(Red-Green-Refactor)

  1. 红:编写一个失败的测试。
  2. 绿:编写代码使测试通过。
  3. 重构:优化代码,确保测试仍然通过。

我们先快速试一下
先写个测试用例

public class CalculatorTest {@Testpublic void testAdd1() {Calculator calculator = new Calculator();assertEquals(3, calculator.add(1, 2));}@Testpublic void testAdd2() {Calculator calculator = new Calculator();assertEquals(0, calculator.add(1, -1));}
}

这个时候,测试用例是通不过的,因为我们的业务代码类都还没实现,编译错误。当然这样体验不太好,我们也可以先实现业务代码的骨架,只是空实现。

public class Calculator {public Integer add(int a, int b) {return null;}
}

我们运行一下测试用例,UT不通过,这也是预期的。
在这里插入图片描述

然后我们开始实现代码

public class Calculator {public Integer add(int a, int b) {return 0;}
}

这时候单元用例部分通过了
在这里插入图片描述
说明我们的代码有问题,继续调整

public class Calculator {public Integer add(int a, int b) {return a + b;}
}

这次我们的UT都过了,表示代码基本没问题了。(基本没问题不表示绝对没问题,因为可能测试覆盖率不够,有些边缘的case没有考虑到。)

下次,我们的业务代码被修改了,理论上出了bug,我们的测试用例是要失败的。

public class Calculator {public Integer add(int a, int b) {if(a < 0 || b < 0){return null;}return a + b;}
}

在这里插入图片描述
这时候,我们就需要注意了,是代码有问题,还是测试用例需要更新。

转换思路——测试先行

UT测试框架

Java最常用的 UT 框架有两个

  1. Junit
  2. TestNG

其中Junit比较轻量,满足大部分场景。TestNG功能更强大,比如支持并行测试(同时运行多个测试用例,Junit只能一个完了后再跑下一个)。具体对比:

  • TestNG 的@DataProvider,注入测试数据更方便,Junit5后提供的@ParameteriedTest也差不多功能
  • TestNG支持测试依赖,运行A用例前会自动先触发B用例
  • TestNG支持测试分组,方便运行一组测试用例
  • TestNG支持用例并行执行,对相对独立的case可以大大加快UT的时间
  • ……

TestNG更强大,但有时简单就好

Mock框架

前面也说过,对于外部依赖,甚至是业务代码其它的类,我们都应该模拟,这样保证我们可以关注被测试的这个类和这个方法。
保证测试用例的能够独立、快速的被测试

有很多Mock框架

  • Mockito:最常用
  • PowerMock:兼容Mockito,功能更强大,比如测试静态方法和私有方法(反思:private方法真的应该被测试吗)

比如使用Mockito,步骤基本都是差不多的,先创建mock对象和行为,然后调用方法,最后验证结果

public class UserServiceTest {@Testpublic void testGetUser() {// 1. 创建 Mock 对象UserRepository mockRepo = mock(UserRepository.class);// 2. 设置 Mock 行为when(mockRepo.findById(1)).thenReturn(new User(1, "John"));// 3. 调用测试方法UserService userService = new UserService(mockRepo);User user = userService.getUser(1);// 4. 验证结果assertEquals("John", user.getName());}
}

3. Spring Test

为什么要用Spring Test

对于Java项目,直接使用TestNG/Junit + Mockito 不就可以了吗?为什么还要用 Spring Test?

以前也有这个疑问,但是如果我们测试Spring 项目时,Junit + Mockito 就有点力不从心了。比如:

  • 注入Spring的配置,比如application-test.xml中配置,注入到Spring容器中去
  • 自动注入Bean,这个做不到,得手动new对象
  • 模拟HTTP请求,这个也做不到,所以Controller测试不了
  • 测试Spring整个应用,也做不到,只能测试单个类

Spring Test就是为了更方便的测试Spring 应用

当然,Spring Test不是要取代 TestNG/Junit + Mockito, 想法,它底层用的还是这些技术。
它只是提供了一堆工具和注解,帮助我们更方便测试Spring应用。

引入Spring Test

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

我们在关联依赖中也可以看到,它自动引入了Junit和Mockito
在这里插入图片描述
这框架本身包含了两个模块

  1. Spring Test 核心模块 spring-boot-test
  2. 自动配置模块 spring-boot-test-autoconfigure: 我们很多自动配置,比如注入
    在这里插入图片描述
    比如在自动配置的模块中,我们可以看到MockMvc的自动配置。这个类我们以后测试会经常遇到。在这里插入图片描述

Spring Test最简单使用

本文我们先来个最简单的例子,测试我们的Controller。

@RestController
@RequestMapping("/tn-users")
public class TnUserController {private TnUserService tnUserService;public TnUserController(TnUserService tnUserService) {this.tnUserService = tnUserService;}@GetMapping("/{id}")public ResponseEntity<TypiUser> getUser(@PathVariable int id) {TypiUser user = tnUserService.getUserById(id);return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();}
}

然后我们编写测试用例

@WebMvcTest(TnUserController.class)
public class TnUserControllerTest {@Autowiredprivate MockMvc mockMvc;@MockitoBeanprivate TnUserService tnUserService;@Test@DisplayName("测试成功查询用户的情况")public void testGetUser() throws Exception {//givenTypiUser mockUser = TypiUser.builder().id(1234).name("Joe").build();//whenwhen(tnUserService.getUserById(eq(1234))).thenReturn(mockUser);//thenmockMvc.perform(get("/tn-users/{id}", 1234)).andExpect(status().isOk()).andExpect(jsonPath("$.id").value(1234)).andExpect(jsonPath("$.name").value("Joe"));}
}

测试通过
在这里插入图片描述
稍微改一下代码,再次运行,会发现报错。

        mockMvc.perform(get("/tn-users/{id}", 1234)).andExpect(status().isBadRequest());

在这里插入图片描述
可以看到,我们现在具备测试Controller层的能力了。如果没有Spring Test,只是靠Mockito基本做不到接口层的测试。

我们先不用关注实现的细节。下一篇文章我们会全面介绍Spring Test的使用。

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

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

相关文章

Chrome 135 版本新特性

Chrome 135 版本新特性 一、Chrome 135 版本浏览器更新 ** 1. 第三方托管账户注册迁移到 OIDC 授权码流程** Chrome 135 将账户注册的登录页面从营销网站迁移到动态网站&#xff0c;同时也将 OpenID Connect (OIDC) 的隐式流程迁移到授权码流程。这样做的目的是进一步提升第…

Docker Swarm集群搭建与管理全攻略

文章目录 一、节点准备二、初始化 manager 节点三、管理 swarm 集群中的 worker 节点1、添加 worker 节点2、查看 worker 节点3、删除 worker 节点 四、管理 swarm 集群服务1、创建服务2、查看服务3、删除服务 五、管理 swarm 节点服务1、节点标签管理2、创建服务3、查看服务4、…

离线语音识别 ( 小语种国家都支持)可定制词组

1产品介绍 离线语音模组采用神经网络算法&#xff0c;支持语音识别、自学习等功能。运用此模组将 AI 技 术赋能产品&#xff0c;升级改造出语音操控的智能硬件 ( 例如风扇、台灯、空调、马桶、按摩椅、运 动相机、行车记录仪等 ) 。支持全球多种语言识别&#xff0c;如中文…

Docker与VNC的使用

https://hub.docker.com/r/dorowu/ubuntu-desktop-lxde-vnc 下载nvc 客户端 https://downloads.realvnc.com/download/file/viewer.files/VNC-Viewer-7.12.0-Windows.exe 服务端 docker pull dorowu/ubuntu-desktop-lxde-vnc#下载成功 docker pull dorowu/ubuntu-desktop-l…

Linux系统学习Day0——了解和熟悉Linux系统的远程终端登录和数据传输

一、Windows系统与Linux系统虚拟机通过桥接进行网络连接 &#xff08;一&#xff09;桥接模式 桥接模式是虚拟机网络连接的一种常见方式&#xff0c;其核心原理是通过虚拟网卡将Linux虚拟机与宿主机的物理网卡建立桥接关系&#xff0c;使虚拟机能够直接接入物理网络。在该模式…

【开题报告+论文+源码】基于springboot的农贸菜市场租位管理系统的设计与实现

项目背景与意义 随着信息技术的快速发展和普及&#xff0c;信息化管理已成为各行业提升运营效率和服务质量的重要手段。农贸菜市场作为城市生活的重要组成部分&#xff0c;其管理效率和服务水平直接关系到市民的日常生活体验。传统的农贸菜市场租位管理方式往往存在信息不对称、…

Codecademy—— 交互式编程学习的乐园

一、网站概述 Codecademy 是一家美国在线学习编程知识的网站&#xff0c;它为编程学习者提供了一种全新的学习方式。在如今众多的编程学习平台中&#xff0c;Codecademy 凭借其独特的优势脱颖而出&#xff0c;吸引了全球数百万用户。其目标是帮助更多人轻松学习编程&#xff0…

WEB安全--XSS--DOM破坏

一、前言 继XSS基础篇后&#xff0c;我们知道了三种类型的XSS&#xff0c;这篇文章主要针对DOM型XSS的原理进行深入解析。 二、DOM型XSS原理 2.1、什么是DOM 以一个形象的比喻&#xff1a; 网页就像是一座房子&#xff0c;而 **DOM** 就是这座房子的“蓝图”或者“结构图”。…

Linux系统远程操作和程序编译

Linux系统远程操作和程序编译 了解和熟悉Linux系统的远程终端登录、远程图形桌面访问、 X图形窗口访问和FTP文件传输操作 网络设置和用户创建&#xff1a; 在虚拟机Ubuntu系统中&#xff0c;将网络连接设置为“桥接模式”&#xff0c;并配置好IP和网关。确保其他Windows 10系统…

linux开发环境

1.虚拟机环境搭建 在 Ubuntu 系统中&#xff0c;打开&#xff08;如图中显示的窗口 &#xff09;常见快捷键有&#xff1a; Ctrl Alt T&#xff1a;这是最常用的打开终端的快捷键组合 &#xff0c;按下后会快速弹出一个新的终端窗口。 在 VMware 虚拟机环境中&#xff0c;若…

蓝桥·20264-祝福语--找连续字串的长度

#include <iostream> using namespace std; int main() {// 请在此输入您的代码//最小字典序&#xff0c;一定是全a&#xff0c;找s的最长字串a,结果就是该字串长度加1&#xff08;t不能是s的子串&#xff09;//所以这道题就变成了&#xff0c;找s中字串a出现的长度strin…

7.第二阶段x64游戏实战-分析人物属性

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;6.第二阶段x64游戏实战-分析人物状态 首先打开人物面板&#xff0c;查看人物的…

数组的常见算法一

注: 本文来自尚硅谷-宋红康仅用来学习备份 6.1 数值型数组特征值统计 这里的特征值涉及到&#xff1a;平均值、最大值、最小值、总和等 **举例1&#xff1a;**数组统计&#xff1a;求总和、均值 public class TestArrayElementSum {public static void main(String[] args)…

汽车电子笔记之:基于Tasking编译器怎么制作库文件并将库文件集成进工程释放

目录 1、概述 2、库工程创建、使用步骤 2.1、选择对应的MCU型号及空工程 2.2、选择需要封装的代码 2.3、将需要封装的代码复制到库工程 2.4、整理库工程工程属性 2.5、预留不生成库的.c源文件 2.6、编译生成.a文件 2.7、将.a集成进工程 2.7.1、创建释放给客户的工程 …

[ctfshow web入门] web29

前置知识 eval: 把字符串按照 PHP 代码来执行&#xff0c;例如eval(“echo 1;”);这个函数拥有回显 system&#xff1a;使php程序执行系统命令&#xff0c;例如&#xff0c;system(“ls”);就是查看当前目录&#xff0c;这个拥有回显 preg_match&#xff1a;查找字符串是否匹配…

7-8 超速判断

模拟交通警察的雷达测速仪。输入汽车速度&#xff0c;如果速度超出60 mph&#xff0c;则显示“Speeding”&#xff0c;否则显示“OK”。 输入格式&#xff1a; 输入在一行中给出1个不超过500的非负整数&#xff0c;即雷达测到的车速。 输出格式&#xff1a; 在一行中输出测…

【GESP】C++二级练习 luogu-B3721 [语言月赛202303] Stone Gambling S

GESP二级练习&#xff0c;多层循环分支练习&#xff0c;难度★✮☆☆☆。 题目题解详见&#xff1a;https://www.coderli.com/gesp-2-luogu-b3721/ 【GESP】C二级练习 luogu-B3721 [语言月赛202303] Stone Gambling S | OneCoderGESP二级练习&#xff0c;多层循环分支练习&am…

深入理解C++面向对象特性之一 多态

欢迎来到干货小仓库&#xff0c;堪比沙漠!!! 从“Hello World”到改变世界&#xff0c;中间隔着千万次再试一次. 1.多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c; 具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的…

蓝桥备赛指南(14):树的直径与重心

树的直径 什么是树的直径&#xff1f;树的直径是树上最长的一条链&#xff0c;当然这条链并不唯一&#xff0c;所以一棵树可能有多条直径。直径由两个顶点u、v来决定&#xff0c;若由一条直径&#xff08;u,v)&#xff0c;则满足一下性质&#xff1a; 1&#xff09;u、v的度数…

AIDD-人工智能药物设计-网络药理学-多组学与网络药理学分析揭示龟龄集治疗少精症的机制

IF6.7|多组学与网络药理学分析揭示龟龄集治疗少精症的机制 2024年10月28日&#xff0c;海军军医大学张卫东教授团队在Phytomedicine&#xff08;IF6.7&#xff09;上发表了题为“Multi-omics and network pharmacology approaches reveal Gui-Ling-Ji alleviates oligoastheno…