三个要点,掌握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构建到页面设计,与传统软件开发几乎没有差异,只是通过低代码可视化模式,减少了构建“增删改查”功能的重复劳动。

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

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

相关文章

lv7 嵌入式开发-网络编程开发 11 TCP管理与UDP协议

目录 1 TCP管理 1.1 三次握手 1.2 四次挥手 1.3 保活计时器 2 wireshark安装及实验 3.1 icmp协议抓包演示 3.2 tcp协议抓包演示 3 UDP协议 3.1 UDP 的主要特点&#xff1a; 4 练习 1 TCP管理 1.1 三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手&#xff1…

[C国演义] 第十三章

第十三章 三数之和四数之和 三数之和 力扣链接 根据题目要求: 返回的数对应的下标各不相同三个数之和等于0不可包含重复的三元组 – – 即顺序是不做要求的 如: [-1 0 1] 和 [0, 1, -1] 是同一个三元组输出答案顺序不做要求 暴力解法: 排序 3个for循环 去重 — — N^3, …

Nginx与Spring Boot的错误模拟实践:探索502和504错误的原因

文章目录 前言502和504区别---都是Nginx返回的access.log和error.log介绍SpringBoot结合Nginx实战502 and 504准备工作Nginx配置host配置SpringBoot 502模拟access.logerror.log 504模拟access.logerror.log 500模拟access.logerror.log 总结 前言 刚工作那会&#xff0c;最常…

nodejs+vue中医体质的社区居民健康管理系统elementui

可以实现首页、中医体质量表、健康文章、健康视频、我的等&#xff0c;在我的页面可以对医生、小区单元、医疗药品等功能进行操作。目前主要的健康管理系统是以西医为主&#xff0c;而为了传扬中医文化&#xff0c;提高全民健康意识&#xff0c;解决人民日益增长的美好生活需要…

CleanMyMac X4.14.1最新版本下载

CleanMyMac X是一个功能强大的Mac清理软件&#xff0c;它的设计理念是提供多个模块&#xff0c;包括垃圾清理、安全保护、速度优化、应用程序管理和文档管理粉碎等&#xff0c;以满足用户的不同需求。软件的界面简洁直观&#xff0c;让用户能够轻松进行日常的清理操作。 使用C…

【uniapp+vue3+ts】请求函数封装,请求和上传文件拦截器

1、uniapp 拦截器 uni.addInterceptor(STRING,OBJECT) 拦截器中包括基础地址、超时时间、添加请求头标识、添加token utils文件夹下新建http.ts 拦截uploadFile文件上传&#xff0c;rquest请求接口 cosnt baseUrl xxxx// 添加拦截器 const httpInterceptor {//拦截前触发i…

好工具分享:阿里云价格计算器_一键计算精准报价

阿里云服务器价格计算器&#xff0c;鼠标选择云服务器ECS实例规格、地域、系统盘、带宽及购买时长即可一键计算出精准报价&#xff0c;阿里云服务器网分享阿里云服务器价格计算器链接地址&#xff1a; 阿里云服务器价格计算器 先打开阿里云服务器ECS页面 aliyunfuwuqi.com/go…

[计算机入门] Windows附件程序介绍(工具类)

3.14 Windows附件程序介绍(工具类) 3.14.1 计算器 Windows系统中的计算器是一个内置的应用程序&#xff0c;提供了基本的数学计算功能。它被设计为一个方便、易于使用的工具&#xff0c;可以满足用户日常生活和工作中的基本计算需求。 以下是计算器程序的主要功能&#xff1a…

Tensorflow、Pytorch和Ray(张量,计算图)

1.深度学习框架&#xff08;Tensorflow、Pytorch&#xff09; 1.1由来 可以追溯到2016年&#xff0c;当年最著名的事件是alphago战胜人类围棋巅峰柯洁&#xff0c;在那之后&#xff0c;学界普遍认为人工智能已经可以在一些领域超过人类&#xff0c;未来也必将可以在更多领域超过…

Linux CentOS7 vim寄存器

计算机中通常所说的寄存器Register一般指的是CPU中的寄存器&#xff0c;用来暂存CPU处理所需要的指令、数据等。 vim中同样也有寄存器&#xff0c;使用的方式和CPU非常类似。 vim中的寄存器(register)作用和windows中的剪切板类似&#xff0c;不过vim中的寄存器不止一个&…

力扣第226翻转二叉数 c++三种方法 +注释

题目 226. 翻转二叉树 简单 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&am…

布局与打包

属性栏直接输入值&#xff0c;比代码更直观方便。 打包&#xff1a;