当前位置: 首页 > news >正文

三个要点,掌握Spring Boot单元测试

单元测试是软件开发中不可或缺的重要环节,它用于验证软件中最小可测试单元的准确性。结合运用Spring Boot、JUnit、Mockito和分层架构,开发人员可以更便捷地编写可靠、可测试且高质量的单元测试代码,确保软件的正确性和质量。

一、介绍

本文将从与单元测试相关的技术主题开始,在技术部分之后,介绍使用Spring Boot、JUnit和Mockito进行单元测试的实践。

二、测试的关键要素

1.单元

单元测试中的单元一词指的是软件中可以单独测试和处理的最小功能部分,通常是指函数、方法、类或模块等独立的代码片段。

2.用例

用例描述了系统使用特定功能或特性的方式,用于理解、设计和测试软件系统的需求。通常包括用户如何与系统进行交互、对系统的期望以及应该实现的结果等详细信息。

3.边界情况

边界情况指的是软件必须处理的特定场景,这些场景包括意外或边界条件,与典型情况有所不同或被认为是罕见的情况。边界情况可以包括意外用户登录、测试限制、异常输入或其他可能导致系统错误或异常行为的情况。在测试过程中,考虑和测试边界情况是非常重要的,因为它们可以帮助开发人员发现潜在的问题并确保系统的鲁棒性和稳定性。

三、单元测试

单元测试涵盖了我们可以考虑并编写的所有可能性。每个单元必须至少有一个测试方法。测试不是为一个方法编写的,而是为一个单元编写的。

可以按照以下顺序编写单元测试:正常路径/用例、边界情况和异常情况。

这些步骤是必不可少的,这样做可以确保单元以正确的方式处理输入,并生成预期的输出,展现出预期的行为。单元测试是及早发现风险和修复错误的最佳方式。通过单元测试,我们可以预防潜在的意外情况,应对生产代码的变更,确保生产代码能够处理各种情况。简而言之,单元测试确保了生产代码的安全性。

关于单元测试的另一个重要事项是要测试业务逻辑,不是在单元测试中测试基础设施代码,基础设施代码可以在集成测试中进行测试。可以考虑使用一些架构模式(如洋葱架构、六边形架构等)来将业务逻辑与基础设施代码分离。

单元测试的另一个优点是速度快,因为它不需要依赖 Spring ApplicationContext。由于上下文的原因,与单元测试相比,同一测试金字塔中的集成测试速度要慢得多。

1.开始编码

在分层架构项目中,业务代码主要位于服务层。这意味着服务层具有单元,需要进行测试。让我们聚焦于最关键的部分。

以下是一段示例代码:

  @Overridepublic String saveUser(User user) {validateUser(user);try {User savedUser = userRepository.save(user);return savedUser.getEmail();} catch (Exception exception) {throw new IllegalArgumentException(E_GENERAL_SYSTEM);}}private void validateUser(User user) {if (Objects.isNull(user.getEmail())) {throw new IllegalArgumentException(E_USER_EMAIL_MUST_NOT_BE_NULL);}if (findByEmail(user.getEmail()).isPresent()) {throw new IllegalArgumentException(E_USER_ALREADY_REGISTERED);}}@Overridepublic Optional<User> findByEmail(String email) {return userRepository.findByEmail(email);}

上述代码中有两个公共方法和一个私有方法,私有方法可以被视为公共方法的一部分。此外,由于代码的复杂性和功能需求,还存在许多可能的场景需要编写多个测试用例来覆盖各种情况,以确保代码的正确性。

2.注解

@ExtendWith用于将Mockito库集成到JUnit测试中。@Test 标记一个方法,使其成为一个测试方法,测试方法包含指定的测试用例,并由 JUnit 自动运行。

在测试过程中,需要模拟正在测试的类的依赖项。之前提到的原因是,由于 Spring ApplicationContext 不会启动,我们无法将依赖项注入到上下文中。@Mock 用于创建一个模拟的依赖项,而 @InjectMocks 则用于将这些模拟的依赖项注入到被测试类中。

@BeforeEach和@AfterEach可用于在每个方法运行之前和之后执行相应的操作。

@ParameterizedTest 用于使用不同的参数值运行重复的测试用例。通过使用 @ValueSource,可以为方法提供不同的参数值,以便进行多次测试。

3.测试方法的三个主要阶段

  • Given: 准备测试用例所需的对象
  • When: 执行必要的操作以运行测试场景
  • Then: 检查或验证预期结果

doReturn/when 用于确定在给定指定参数时方法的行为方式。但是,由于依赖项是 @Mock,并不会真正执行。

verify 用于检查被测试代码是否按照预期行为执行。如果要测试的方法是 public void 类型,可以使用 verify 进行验证。

断言用于验证预期结果。

 @ExtendWith(MockitoExtension.class)
class UserServiceImplTest {@InjectMocksprivate UserServiceImpl userService;@Mockprivate UserRepository userRepository;private User user;public static final String MOCK_EMAIL = "mert@bahardogan.com";@BeforeEachvoid setUp() {user = new User();System.out.println("init");}@AfterEachvoid teardown() {System.out.println("teardown");}@ParameterizedTest@ValueSource(strings = {"mert@bahardogan.com", "info@gmail.com"})@DisplayName("Happy Path: save user use cases")void givenCorrectUser_whenSaveUser_thenReturnUserEmail(String email) {// givenuser.setUserName("mertbahardogan").setEmail(email).setPassword("pass");User savedUser = new User().setEmail(email);doReturn(savedUser).when(userRepository).save(any());// whenString savedUserEmail = userService.saveUser(user);// thenverify(userRepository,times(1)).findByEmail(anyString());verify(userRepository,times(1)).save(any());assertEquals(email, savedUserEmail);}@Test@DisplayName("Exception Test: user email must not be null case")void givenNullUserEmail_whenSaveUser_thenThrowsEmailMustNotNullEx() {// whenException exception = assertThrows(IllegalArgumentException.class, () -> userService.saveUser(user));// thenassertNotNull(exception);assertEquals(E_USER_EMAIL_MUST_NOT_BE_NULL, exception.getMessage());}@Test@DisplayName("Exception Test: user is already registered case")void givenRegisteredUser_whenSaveUser_thenThrowsUserAlreadyRegisteredEx() {// givenuser.setEmail(MOCK_EMAIL);Optional<User> savedUser = Optional.of(new User().setEmail(MOCK_EMAIL));doReturn(savedUser).when(userRepository).findByEmail(anyString());// whenException exception = assertThrows(IllegalArgumentException.class, () -> userService.saveUser(user));// thenassertNotNull(exception);assertEquals(E_USER_ALREADY_REGISTERED, exception.getMessage());}@Test@DisplayName("Exception Test: catch case")void givenIncorrectDependencies_whenSaveUser_thenThrowsGeneralSystemEx() {// givenuser.setEmail(MOCK_EMAIL);// whenException exception = assertThrows(IllegalArgumentException.class, () -> userService.saveUser(user));// thenassertNotNull(exception);assertEquals(E_GENERAL_SYSTEM, exception.getMessage());}@Test@DisplayName("Happy Path: find user by email")void givenCorrectUser_whenFindByEmail_thenReturnUserEmail() {// givenOptional<User> savedUser = Optional.of(new User().setEmail(MOCK_EMAIL));doReturn(savedUser).when(userRepository).findByEmail(anyString());// whenOptional<User> user = userService.findByEmail(MOCK_EMAIL);// thenverify(userRepository,times(1)).findByEmail(anyString());assertEquals(savedUser, user);}
}

UserServiceImpl测试类运行时长为1秒693毫秒。

介绍一款软件开发工具

成功的前端工程师很会善用工具,这些年低代码概念开始流行,像国外的 Mendix,国内的 JNPF,这种新型的开发方式,图形化的拖拉拽配置界面,并兼容了自定义的组件、代码扩展,确实在 B 端后台管理类网站建设中很大程度上的提升了效率。

JNPF开发平台,很多人都用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。

原理是将开发过程中某些重复出现的场景、流程,具象化成一个个组件、api、数据库接口,避免了重复造轮子。因而极大的提高了程序员的生产效率。

官网:http://www.jnpfsoft.com/?csdn,如果你有闲暇时间,可以做个知识拓展。

这是一个基于Java Boot/.Net Core构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,满足快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的Demo方便直接使用;后端框架支持Vue2、Vue3。

为了支撑更高技术要求的应用开发,从数据库建模、Web API构建到页面设计,与传统软件开发几乎没有差异,只是通过低代码可视化模式,减少了构建“增删改查”功能的重复劳动。

相关文章:

三个要点,掌握Spring Boot单元测试

单元测试是软件开发中不可或缺的重要环节&#xff0c;它用于验证软件中最小可测试单元的准确性。结合运用Spring Boot、JUnit、Mockito和分层架构&#xff0c;开发人员可以更便捷地编写可靠、可测试且高质量的单元测试代码&#xff0c;确保软件的正确性和质量。 一、介绍 本文…...

【nginx】Nginx配置:

文章目录 一、什么是Nginx&#xff1a;二、为什么使用Nginx&#xff1a;三、如何处理请求&#xff1a;四、什么是正向代理和反向代理&#xff1a;五、nginx 启动和关闭&#xff1a;六、目录结构&#xff1a;七、配置文件nginx.conf&#xff1a;八、location&#xff1a;九、单页…...

CSS3与HTML5

box-sizing content-box&#xff1a;默认&#xff0c;宽高包不含边框和内边距 border-box&#xff1a;也叫怪异盒子&#xff0c;宽高包含边框和内边距 动画&#xff1a;移动translate&#xff0c;旋转、transform等等 走马灯&#xff1a;利用动画实现animation&#xff1a;from…...

redis的简单使用

文章目录 环境安装与配置redis发布-订阅相关命令redis发布-订阅的客户端编程redis的订阅发布的例子 环境安装与配置 sudo apt-get install redis-server # ubuntu命令安装redis服务ubuntu通过上面命令安装完redis&#xff0c;会自动启动redis服务&#xff0c;通过ps命令确认&a…...

Windows下启动freeRDP并自适应远端桌面大小

几个二进制文件 xfreerdp # Linux下的&#xff0c;an X11 Remote Desktop Protocol (RDP) client which is part of the FreeRDP project wfreerdp.exe # Windows下的&#xff0c;freerdp2.0 主程序&#xff0c;freerdp3.0将废弃 sdl-freerdp.exe # Windows下的&…...

ES6中的数值扩展

1. 二进制和八进制的表示法 二进制和八进制的前缀分别为0b(或0B)和0o(或0O)表示 在ES5的严格模式下&#xff0c;八进制不再允许使用前缀0表示 如果要将0b和0x前缀的字符串数值转为十进制&#xff0c;要使用Number方法 Number(0b111); // 7 Number(0o10); // 82. Number.isF…...

自定义注解实现Redis分布式锁、手动控制事务和根据异常名字或内容限流的三合一的功能

自定义注解实现Redis分布式锁、手动控制事务和根据异常名字或内容限流的三合一的功能 文章目录 [toc] 1.依赖2.Redisson配置2.1单机模式配置2.2主从模式2.3集群模式2.4哨兵模式 3.实现3.1 RedisConfig3.2 自定义注解IdempotentManualCtrlTransLimiterAnno3.3自定义切面Idempote…...

Linux:minishell

目录 1.实现逻辑 2.代码及效果展示 1.打印字符串提示用户输入指令 2.父进程拆解指令 3.子进程执行指令,父进程等待结果 4.效果 3.实现过程中遇到的问题 1.打印字符串的时候不显示 2.多换了一行 3.cd路径无效 4.优化 1.ll指令 2.给文件或目录加上颜色 代码链接 模…...

STM32驱动步进电机

前言 &#xff08;1&#xff09;本章介绍用stm32驱动42步进电机&#xff0c;将介绍需要准备的硬件器材、所需芯片资源以及怎么编程及源代码等等。 &#xff08;2&#xff09;实验效果&#xff1a;按下按键&#xff0c;步进电机顺时针或逆时针旋转90度。 &#xff08;3&#xff…...

计算机视觉——飞桨深度学习实战-深度学习网络模型

深度学习网络模型的整体架构主要数据集、模型组网以及学习优化过程三部分&#xff0c;本章主要围绕着深度学习网络模型的算法架构、常见模型展开了详细介绍&#xff0c;从经典的深度学习网络模型以CNN、RNN为代表&#xff0c;到为了解决显存不足、实时性不够等问题的轻量化网络…...

用c动态数组(不用c++vector)实现手撸神经网咯230901

用c语言动态数组(不用c++的vector)实现:输入数据inputs = { {1, 1}, {0,0},{1, 0},{0,1} };目标数据targets={0,0,1,1}; 测试数据 inputs22 = { {1, 0}, {1,1},{0,1} }; 构建神经网络,例如:NeuralNetwork nn({ 2, 4,3,1 }); 则网络有四层、输入层2个nodes、输出层1个节点、第…...

视频讲解|基于DistFlow潮流的配电网故障重构代码

目录 1 主要内容 2 视频链接 1 主要内容 该视频为基于DistFlow潮流的配电网故障重构代码讲解内容&#xff0c;对应的资源下载链接为基于DistFlow潮流的配电网故障重构(输入任意线路)&#xff0c;对该程序进行了详尽的讲解&#xff0c;基本做到句句分析和讲解&#xff08;讲解…...

Ultralytics(YoloV8)开发环境配置,训练,模型转换,部署全流程测试记录

关键词&#xff1a;windows docker tensorRT Ultralytics YoloV8 配置开发环境的方法&#xff1a; 1.Windows的虚拟机上配置&#xff1a; Python3.10 使用Ultralytics 可以得到pt onnx&#xff0c;但无法转为engine&#xff0c;找不到GPU&#xff0c;手动转也不行&#xff0…...

springboot之@ImportResource:导入Spring配置文件~

ImportResource的作用是允许在Spring配置文件中导入其他的配置文件。通过使用ImportResource注解&#xff0c;可以将其他配置文件中定义的Bean定义导入到当前的配置文件中&#xff0c;从而实现配置文件的模块化和复用。这样可以方便地将不同的配置文件进行组合&#xff0c;提高…...

阿里云服务器免费申请入口_注册阿里云免费领4台服务器

注册阿里云账号&#xff0c;免费领云服务器&#xff0c;最高领取4台云服务器&#xff0c;每月750小时&#xff0c;3个月免费试用时长&#xff0c;可快速搭建网站/小程序&#xff0c;部署开发环境&#xff0c;开发多种企业应用。阿里云百科分享阿里云服务器免费领取入口、免费云…...

ES6中的async、await函数

async是为了解决异步操作&#xff0c;其实是一个语法糖&#xff0c;使代码书写更加简洁。 1. async介绍 async放在一个函数的前面&#xff0c;await则放在异步操作前面。async代表这个函数中有异步操作需要等待结果&#xff0c;在一个async函数中可以存在多个await&#xff0…...

代码随想录算法训练营第五十六天 | 动态规划 part 14 | 1143.最长公共子序列、1035.不相交的线、53. 最大子序和(dp)

目录 1143.最长公共子序列思路代码 1035.不相交的线思路代码 53. 最大子序和&#xff08;dp&#xff09;思路代码 1143.最长公共子序列 Leetcode 思路 本题和718. 最长重复子数组 区别在于这里不要求是连续的了&#xff0c;但要有相对顺序&#xff0c;即&#xff1a;“ace” …...

【数据挖掘】2021年 Quiz 1-3 整理 带答案

目录 Quiz 1Quiz 2Quiz 3Quiz 1 Problem 1 (30%). Consider the training data shown below. Here, A A A and B B B</...

【软件设计师-中级——刷题记录6(纯干货)】

目录 管道——过滤器软件体系结构风格优点&#xff1a;计算机英语重点词汇&#xff1a;单元测试主要检查模块的以下5个特征&#xff1a;数据库之并发控制中的事务&#xff1a;并发产生的问题解决方案:封锁协议原型化开发方法&#xff1a; 每日一言&#xff1a;持续更新中... 个…...

微信小程序点单左右联动的效果实现

微信小程序点单左右联动的效果实现 原理解析&#xff1a;   点击左边标签会跳到右边相应位置&#xff1a;点击改变rightCur值&#xff0c;转跳相应位置滑动右边&#xff0c;左边标签会跳到相应的位置&#xff1a;监听并且设置每个右边元素的top和bottom&#xff0c;再判断当…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...