Spring Boot 单元测试使用教程(仅供参考)

        单元测试是软件开发中至关重要的一环,Spring Boot 提供了强大的测试支持。以下是 Spring Boot 单元测试的详细教程。


1. 准备工作

1.1 添加测试依赖

在 pom.xml 中添加测试相关依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency><!-- 如果需要MockMvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><scope>test</scope>
</dependency><!-- 如果需要AssertJ -->
<dependency><groupId>org.assertj</groupId><artifactId>assertj-core</artifactId><version>3.24.2</version><scope>test</scope>
</dependency>

1.2 测试类基本结构

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class MyApplicationTests {@Testpublic void contextLoads() {// 测试Spring上下文是否正常加载}
}

2. 不同类型的测试

2.1 服务层测试

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;@ExtendWith(MockitoExtension.class)
public class UserServiceTest {@Mockprivate UserRepository userRepository;@InjectMocksprivate UserService userService;@Testpublic void testGetUserById() {// 准备测试数据User mockUser = new User(1L, "test@example.com", "Test User");// 定义mock行为when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));// 调用测试方法User result = userService.getUserById(1L);// 验证结果assertEquals("Test User", result.getName());verify(userRepository, times(1)).findById(1L);}
}

2.2 控制器层测试

使用MockMvc
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {@Autowiredprivate MockMvc mockMvc;@Testpublic void testGetUser() throws Exception {mockMvc.perform(get("/api/users/1")).andExpect(status().isOk()).andExpect(jsonPath("$.name").value("Test User"));}
}
使用WebTestClient (WebFlux)
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;@SpringBootTest
@AutoConfigureWebTestClient
public class UserControllerWebTestClientTest {@Autowiredprivate WebTestClient webTestClient;@Testpublic void testGetUser() {webTestClient.get().uri("/api/users/1").exchange().expectStatus().isOk().expectBody().jsonPath("$.name").isEqualTo("Test User");}
}

2.3 数据库测试

使用@DataJpaTest
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import static org.assertj.core.api.Assertions.*;@DataJpaTest
public class UserRepositoryTest {@Autowiredprivate TestEntityManager entityManager;@Autowiredprivate UserRepository userRepository;@Testpublic void testFindByEmail() {// 准备测试数据User user = new User("test@example.com", "Test User");entityManager.persist(user);entityManager.flush();// 调用测试方法User found = userRepository.findByEmail(user.getEmail());// 验证结果assertThat(found.getEmail()).isEqualTo(user.getEmail());}
}
使用@SpringBootTest + 测试数据库
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class UserServiceIntegrationTest {@Autowiredprivate UserService userService;@Autowiredprivate UserRepository userRepository;@Testpublic void testCreateUser() {User newUser = new User("new@example.com", "New User");User savedUser = userService.createUser(newUser);assertNotNull(savedUser.getId());assertEquals("New User", savedUser.getName());User found = userRepository.findById(savedUser.getId()).orElse(null);assertEquals("New User", found.getName());}
}

3. 常用测试技巧

3.1 参数化测试

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;public class ParameterizedTests {@ParameterizedTest@ValueSource(strings = {"racecar", "radar", "madam"})public void testPalindromes(String candidate) {assertTrue(StringUtils.isPalindrome(candidate));}
}

3.2 测试异常

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;public class ExceptionTest {@Testpublic void testException() {UserService userService = new UserService();assertThrows(UserNotFoundException.class, () -> {userService.getUserById(999L);});}
}

3.3 测试私有方法

虽然不推荐直接测试私有方法,但有时确实需要:

import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;public class PrivateMethodTest {@Testpublic void testPrivateMethod() throws Exception {MyService service = new MyService();Method method = MyService.class.getDeclaredMethod("privateMethod", String.class);method.setAccessible(true);String result = (String) method.invoke(service, "input");assertEquals("expected", result);}
}

4. 测试配置

4.1 使用测试配置文件

创建 src/test/resources/application-test.properties

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true

然后在测试类上使用:

@ActiveProfiles("test")

4.2 使用测试切片

Spring Boot 提供了多种测试切片注解:

  • @WebMvcTest - 只测试MVC层

  • @DataJpaTest - 只测试JPA组件

  • @JsonTest - 只测试JSON序列化

  • @RestClientTest - 只测试REST客户端

    @WebMvcTest(UserController.class)
    public class UserControllerSliceTest {@Autowiredprivate MockMvc mockMvc;@MockBeanprivate UserService userService;@Testpublic void testGetUser() throws Exception {when(userService.getUserById(1L)).thenReturn(new User(1L, "test@example.com", "Test User"));mockMvc.perform(get("/api/users/1")).andExpect(status().isOk()).andExpect(jsonPath("$.name").value("Test User"));}
    }


5. 测试最佳实践

  1. 命名规范:测试方法名应清晰表达测试意图,如 shouldReturnUserWhenValidIdProvided()

  2. 单一职责:每个测试方法只测试一个功能点

  3. AAA模式:遵循Arrange-Act-Assert模式组织测试代码

  4. 避免依赖:测试之间不应有依赖关系

  5. 快速反馈:保持测试快速执行,避免I/O操作

  6. 覆盖率:追求合理的测试覆盖率,但不要盲目追求100%

  7. Mock适度:不要过度使用mock,集成测试也很重要


6. 高级主题

6.1 自定义测试注解

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootTest
@ActiveProfiles("test")
public @interface MyIntegrationTest {
}

然后可以在测试类上使用 @MyIntegrationTest 替代多个注解。

6.2 测试容器支持

使用Testcontainers进行集成测试:

import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;@Testcontainers
@SpringBootTest
public class UserRepositoryTestContainersTest {@Containerpublic static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:13").withDatabaseName("testdb").withUsername("test").withPassword("test");@Testpublic void testWithRealDatabase() {// 测试代码}
}

6.3 测试Spring Security

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@SpringBootTest
@AutoConfigureMockMvc
public class SecuredControllerTest {@Autowiredprivate MockMvc mockMvc;@Test@WithMockUser(username="admin", roles={"ADMIN"})public void testAdminEndpoint() throws Exception {mockMvc.perform(get("/api/admin")).andExpect(status().isOk());}@Test@WithMockUser(username="user", roles={"USER"})public void testAdminEndpointForbidden() throws Exception {mockMvc.perform(get("/api/admin")).andExpect(status().isForbidden());}
}

7. 总结

Spring Boot 提供了全面的测试支持,从单元测试到集成测试,从Mock测试到真实环境测试。合理使用这些工具可以大大提高代码质量和开发效率。

记住测试金字塔原则:多写单元测试,适量集成测试,少量端到端测试。

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

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

相关文章

React Hooks速成

1、useReducer 适用情况为对一个状态多种复杂操作,通俗的讲就是比如对count这个变量加减乘除的各种情况 改造前 import { useState } from "react";function App() {//计数器const [count, setCount] useState(0);const handleIncrement () > {setCount(coun…

k8s node 内存碎片化如何优化?

在 Kubernetes 集群中&#xff0c;内存碎片化&#xff08;Memory Fragmentation&#xff09;会导致系统无法分配连续的内存块&#xff0c;即使总内存充足&#xff0c;也可能触发 OOM&#xff08;Out of Memory&#xff09;或影响性能。以下是针对 k8s Node 内存碎片化的优化策略…

目标检测(Object Detection)研究方向常用数据集简单介绍

目录 一、目标检测研究方向简介 二、目标检测常用数据集详解 通用目标检测数据集 领域专用数据集 三、数据集选择建议 一、目标检测研究方向简介 目标检测是计算机视觉的核心任务之一&#xff0c;旨在从图像或视频中定位并识别出所有感兴趣的物体&#xff0c;输出其类别和…

即开即用,封装 Flask 项目为 exe 文件实操步骤

见字如面&#xff0c;朋友们&#xff01; 嗨&#xff0c;这里是 AIGC 创意人_竹相左边&#xff01; 正如你们所知&#xff0c;我正在通过 AI 自学软硬件工程师&#xff0c;目标是手搓一台可回收火箭玩具&#xff01; 最近&#xff0c;我被《流浪地球 2》中马兆的那句“没有硬…

uniapp开发微信小程序时如何进行分包(新手图文)

我们在进行uniapp微信小程序开发的时候&#xff0c;每次上传都提示包太大&#xff0c;主包大小不能超过 2M&#xff0c; 这就很头疼&#xff0c;这个时候&#xff0c;唯一的解决方案就是分包了&#xff0c;那如何进行分包呢&#xff1f; 分包步骤如下&#xff1a; 一、配置man…

基于C++的IOT网关和平台2:github项目ctGateway技术说明书

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。 源码指引:github源码指引_初级代码游戏的博客-CSDN博客 系…

从巴别塔到通天塔:Manus AI 如何重构多语言手写识别的智能版图

一、引言&#xff1a;当人类手写遇上 AI “巴别塔” 在幼发拉底河畔的古老传说中&#xff0c;巴别塔的崩塌象征着人类语言互通的终结。而在数字时代&#xff0c;全球 7000 余种语言的手写文字&#xff0c;正成为横亘在人机交互之间的新 “巴别塔”—— 阿拉伯文的连笔天书、中…

n8n 快速入门2:构建自动化工作流

n8n 快速入门2:构建自动化工作流 什么是n8n?项目目标准备工作步骤一:创建新工作流步骤二:添加触发节点步骤三:配置NASA节点与凭证1. 添加NASA节点2. 设置NASA API凭证3. 使用表达式设置时间范围步骤四:添加If条件节点1. 创建条件分支2. 测试条件逻辑步骤五:配置输出节点…

从实列中学习linux shell10 : 如何根据服务器的内存,cpu 以及 ssd硬盘 来确定mysql 的最大并发数

以下是根据服务器硬件资源智能推荐MySQL最大并发连接数 包含详细的计算逻辑和实时资源检测&#xff1a; 且记&#xff1a;该脚本要放在 安装mysql的服务器上 运行 第一步&#xff1a;实现脚本 #!/bin/bash# 计算MySQL最大连接数推荐值 # 公式说明&#xff1a;取CPU计算值与内…

数据结构--AVL树

目录 前言 AVL树的特点 AVL树的插入 节点的定义 情况分析 AVL树的旋转 右单旋 左单旋 左右双旋 右左双旋 ​编辑总结 验证AVL树 前言 二叉搜索树可以帮助我们以极高的效率查找(理想情况下是logn)&#xff0c;但是当在极端情况下&#xff0c;比如当树中的节点值是有…

泰迪杯特等奖案例学习资料:基于多模态融合与边缘计算的智能温室环境调控系统

(第十二届泰迪杯数据挖掘挑战赛特等奖案例解析) 一、案例背景与核心挑战 1.1 应用场景与行业痛点 在现代设施农业中,温室环境调控直接影响作物产量与品质。传统温室管理存在以下问题: 环境参数耦合性高:温度、湿度、光照、CO₂浓度等参数相互影响,人工调控易顾此失彼。…

动手学深度学习12.1. 编译器和解释器-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;无 本节教材地址&#xff1a;12.1. 编译器和解释器 — 动手学深度学习 2.0.0 documentation 本节…

[java八股文][Java并发编程面试篇]并发安全

juc包下你常用的类&#xff1f; 线程池相关&#xff1a; ThreadPoolExecutor&#xff1a;最核心的线程池类&#xff0c;用于创建和管理线程池。通过它可以灵活地配置线程池的参数&#xff0c;如核心线程数、最大线程数、任务队列等&#xff0c;以满足不同的并发处理需求。Exe…

VMware搭建ubuntu保姆级教程

目录 VMware Ubuntu 虚拟机配置指南 创建虚拟机 下载 Ubuntu ISO 新建虚拟机 网络配置&#xff08;双网卡模式&#xff09; 共享文件夹设置 SSH 远程访问配置 VMware Ubuntu 虚拟机配置指南 创建虚拟机 下载 Ubuntu ISO 【可添加我获取】 官网&#xff1a;Get Ubunt…

冯诺依曼结构与哈佛架构深度解析

一、冯诺依曼结构&#xff08;Von Neumann Architecture&#xff09; 1.1 核心定义 由约翰冯诺依曼提出&#xff0c;程序指令与数据共享同一存储空间和总线&#xff0c;通过分时复用实现存取。 存储器总带宽 指令带宽 数据带宽 即&#xff1a;B_mem f_clk W_data f_…

C/C++工程中的Plugin机制设计与Python实现

C/C工程中的Plugin机制设计与Python实现 1. Plugin机制设计概述 在C/C工程中实现Plugin机制通常需要以下几个关键组件&#xff1a; Plugin接口定义&#xff1a;定义统一的接口规范动态加载机制&#xff1a;运行时加载动态库注册机制&#xff1a;Plugin向主程序注册自己通信机…

node-sass安装失败解决方案

1、python环境问题 Error: Cant find Python executable "python", you can set the PYTHON env variable. 提示找不到python2.7版本&#xff0c; 方法一&#xff1a;可安装一个python2.7或引用其他已安装的python2.7 通过设置环境变量可以解决&#xff1b; 方法二&…

Netty高并发物联网通信服务器实战:协议优化与性能调优指南

目录 1.总体设计 2.自定义协议设计(简单版) 3.消息类型(1字节) 4.项目结构 5.核心功能代码 (1)pom.xml(Maven依赖) (2)IotServer.java(服务器启动器) (3)IotServerInitializer.java(Pipeline初始化) (4)DeviceChannelManager.java(设备连接管理器)…

多模态大语言模型arxiv论文略读(六十)

Cantor: Inspiring Multimodal Chain-of-Thought of MLLM ➡️ 论文标题&#xff1a;Cantor: Inspiring Multimodal Chain-of-Thought of MLLM ➡️ 论文作者&#xff1a;Timin Gao, Peixian Chen, Mengdan Zhang, Chaoyou Fu, Yunhang Shen, Yan Zhang, Shengchuan Zhang, Xi…

面试常问系列(一)-神经网络参数初始化-之自注意力机制为什么除以根号d而不是2*根号d或者3*根号d

首先先罗列几个参考文章&#xff0c;大家之后可以去看看&#xff0c;加深理解&#xff1a; 面试常问系列(一)-神经网络参数初始化面试常问系列(一)-神经网络参数初始化之自注意力机制_注意力机制的参数初始化怎么做-CSDN博客面试常问系列(一)-神经网络参数初始化-之-softmax-C…