在 SpringBoot 实际开发中,我们写的单元测试(比如只测试 Service 层单个方法),往往只能覆盖局部逻辑,却忽略了一个关键问题:单个方法没问题,不代表整个调用链路没问题。
比如:Controller 层的参数校验是否生效?拦截器是否正常拦截请求?Service 层调用 Mapper 层后数据返回是否符合预期?接口的异常处理是否正确?这些场景,单元测试无法覆盖,必须靠集成测试来验证。
一、集成测试 vs 单元测试
很多同学分不清单元测试和集成测试,导致测试写得冗余、无效,先用一张表彻底区分,后续写测试才不会跑偏:
| 对比维度 | 单元测试 | SpringBoot 集成测试 |
|---|---|---|
| 测试范围 | 单个类、单个方法(如 Service 单个方法) | 全链路(Controller → Service → Mapper → 数据库/第三方接口) |
| 是否加载 Spring 上下文 | 不加载,靠 Mock 模拟依赖(如 Mock Service) | 加载完整 Spring 上下文,Bean 真实注入 |
| 核心工具 | JUnit、Mockito | @SpringBootTest、MockMvc、TestContainers(可选) |
| 测试速度 | 快(毫秒级),无需启动上下文 | 慢(秒级),需加载配置、启动上下文 |
| 适用场景 | 验证单个方法的逻辑正确性 | 验证接口全链路、配置生效、依赖调用正确性 |
简单总结:单元测试测「点」,保证单个方法不出错;集成测试测「线」,保证整个接口链路能正常跑通。两者结合,才能最大化保证代码质量。
而我们今天的主角:@SpringBootTest 是集成测试的「入口」,负责启动 Spring 上下文;MockMvc 是集成测试的「工具」,负责模拟 HTTP 请求,无需启动真实服务器就能测试接口。
二、环境准备:依赖配置 + 项目结构
首先明确:SpringBoot 2.2+ 版本后,默认集成了 spring-boot-starter-test 依赖,无需额外手动添加,但如果是老项目或依赖缺失,需手动补充,同时建议指定版本(和 SpringBoot 版本一致)。
2.1 核心依赖配置(pom.xml)
go
<!-- SpringBoot 测试核心依赖(包含 JUnit 5、MockMvc、Mockito 等) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- 若需指定版本,与 SpringBoot 版本保持一致 -->
<!-- <version>2.7.10</version> -->
</dependency>
<!-- 可选:若测试中需要操作数据库,添加数据库依赖(示例 MySQL) -->
<dependency>
<groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
<scope>test</scope>
</dependency>
<!-- 可选:若需模拟第三方接口,添加 OkHttp 依赖 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<scope>test</scope>
<version>4.11.0</version>
</dependency>
2.2 项目测试结构
建议遵循 SpringBoot 测试规范,测试类与业务类包路径一致,便于维护,示例结构:
go
com.example.demo
├── DemoApplication.java // 项目启动类
├── controller
│ └── UserController.java // 业务接口类
├── service
│ └── UserService.java // 业务逻辑类
├── mapper
│ └── UserMapper.java // 数据访问类
└── src/test/java
└── com.example.demo
├── controller
│ └── UserControllerTest.java // Controller 层集成测试
├── service
│ └── UserServiceTest.java // Service 层集成测试(可混合单元测试)
└── DemoApplicationTests.java // 全局集成测试入口
三、 @SpringBootTest:
很多开发者用 @SpringBootTest 只知道加个注解就完事,却不知道它的底层原理和灵活配置,导致测试效率低、冗余。今天彻底拆解它的核心用法和进阶配置。
3.1 底层原理
@SpringBootTest 本质是一个「上下文启动器」,它会扫描项目中的 @SpringBootApplication 启动类,加载所有配置(application.yml/properties、配置类、Bean 定义),创建一个完整的 Spring 应用上下文,让测试类能像真实运行环境一样,注入所有 Bean(Service、Mapper、Controller 等)。
注意:它默认不会启动内嵌服务器(如 Tomcat),除非指定 webEnvironment 属性。
3.2 核心配置属性
@SpringBootTest 有多个配置属性,日常开发中最常用的有 3 个,结合场景灵活使用:
(1)classes:指定启动类
默认情况下,@SpringBootTest 会自动查找项目中唯一的 @SpringBootApplication 注解类作为启动类,无需手动指定。但如果项目中有多个启动类(如多模块项目),就必须手动指定,否则会报错。
go
// 多模块项目中,手动指定启动类
@SpringBootTest(classes = DemoApplication.class)
public class UserControllerTest {
// 测试代码
}
(2)webEnvironment:指定 Web 环境
这是最常用的属性,决定了测试的 Web 环境模式,有 4 个可选值,重点记前 3 个:
-
• WebEnvironment.MOCK(默认):模拟 Web 环境,不启动真实内嵌服务器(Tomcat),适合配合 MockMvc 测试接口(最常用);
-
• WebEnvironment.RANDOM_PORT:启动真实内嵌服务器,随机分配一个端口,适合测试真实 HTTP 请求(如测试拦截器、过滤器、跨域配置);
-
• WebEnvironment.DEFINED_PORT:启动真实内嵌服务器,使用配置文件中指定的端口(如 application.yml 中的 server.port);
-
• WebEnvironment.NONE:不启动 Web 环境,适合测试非 Web 项目(如纯 Service、Mapper 层测试)。
示例:使用随机端口启动真实服务器,测试真实 HTTP 请求:
go
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RealHttpTest {
// 注入随机端口(通过 @LocalServerPort 注解)
@LocalServerPort
private int port;
// 用 OkHttp 发起真实 HTTP 请求
private OkHttpClient okHttpClient = new OkHttpClient();
@Test
public void testRealHttp() throws IOException {
// 构建请求地址(随机端口)
String url = "http://localhost:" + port + "/user/1";
Request request = new Request.Builder().url(url).build();
Response response = okHttpClient.newCall(request).execute();
// 校验响应状态码
Assertions.assertEquals(200, response.code());
}
}
(3)properties:临时覆盖配置
测试环境中,我们可能需要临时覆盖配置文件中的参数(如数据库地址、第三方接口地址),无需修改 application.yml,直接通过 properties 属性指定即可,优先级高于配置文件。
go
// 临时覆盖数据库地址、日志级别,仅在测试中生效
@SpringBootTest(properties = {
"spring.datasource.url=jdbc:mysql://localhost:3306/test_db",
"logging.level.com.example.demo=DEBUG"
})
public class ConfigOverrideTest {
// 测试代码
}
3.3 基础使用示例(Service 层集成测试)
集成测试中,我们可以直接注入 Service、Mapper 等 Bean,测试业务逻辑的完整调用(包括数据库操作),示例:
go
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class UserServiceIntegrationTest {
// 直接注入真实的 UserService(非 Mock)
@Autowired
private UserService userService;
// 直接注入真实的 UserMapper
@Autowired
private UserMapper userMapper;
/**
* 测试:根据 ID 查询用户(全链路:Service → Mapper → 数据库)
*/
@Test
public void testGetUserById() {
// 1. 先插入测试数据(避免依赖数据库原有数据)
User testUser = new User(null, "测试用户", 25, "13800138000");
userMapper.insert(testUser);
Long userId = testUser.getId();
// 2. 调用 Service 方法
User resultUser = userService.getUserById(userId);
// 3. 校验结果
assertNotNull(resultUser);
assertEquals("测试用户", resultUser.getUsername());
assertEquals(25, resultUser.getAge());
// 4. 清理测试数据(避免污染数据库)
userMapper.deleteById(userId);
}
}
注意:这里没有用 Mock,而是直接操作真实数据库,适合验证数据层和业务层的联动正确性。
四、MockMvc 进阶
MockMvc 是 Spring Test 提供的 HTTP 请求模拟工具,核心优势是:无需启动真实服务器,就能模拟 GET、POST、PUT、DELETE 等所有 HTTP 请求,并精准校验响应结果(状态码、响应体、响应头、Cookie 等),是 Controller 层集成测试的必备工具。
很多开发者只用过它的基础方法,今天分享实战中高频的进阶用法,覆盖大部分接口测试场景。
4.1 两种初始化方式
MockMvc 的初始化有两种方式,根据场景选择,推荐第一种(简单高效):
方式1:@AutoConfigureMockMvc 自动注入
在 @SpringBootTest 注解下,添加 @AutoConfigureMockMvc 注解,Spring 会自动配置 MockMvc 实例,直接注入即可使用,无需手动构建,适合大多数场景。
go
@SpringBootTest
@AutoConfigureMockMvc // 自动配置 MockMvc
public class UserControllerTest {
// 直接注入 MockMvc 实例
@Autowired
private MockMvc mockMvc;
// 测试方法...
}
方式2:手动构建
如果需要自定义 MockMvc 配置(如添加拦截器、过滤器、异常处理器),可以通过 WebApplicationContext 手动构建,灵活度更高。
go
@SpringBootTest
public class CustomMockMvcTest {
private MockMvc mockMvc;
// 注入 Web 应用上下文
@Autowired
private WebApplicationContext webApplicationContext;
// 测试方法执行前,初始化 MockMvc(@BeforeEach 是 JUnit 5 注解,替代 JUnit 4 的 @Before)
@BeforeEach
public void setUp() {
// 手动构建 MockMvc,可添加自定义配置(如添加拦截器)
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
// 模拟文件上传(可选)
.addFileUpload(new MockMultipartFile("file", "test.txt", "text/plain", "test content".getBytes()))
// 全局异常处理(可选,若项目有自定义异常处理器,可省略)
.setControllerAdvice(new GlobalExceptionHandler())
.build();
}
// 测试方法...
}
4.2 核心方法详解
MockMvc 的所有操作都遵循「发起请求 → 配置请求 → 校验响应」的固定套路,核心方法整理如下,结合示例理解,记熟就能直接用:
(1)发起请求:perform()
所有请求的入口,参数是一个 RequestBuilder 对象,常用的 RequestBuilder 由 MockMvcRequestBuilders 提供,如 get()、post()、put()、delete()。
go
// 发起 GET 请求
mockMvc.perform(get("/user/1"));
// 发起 POST 请求
mockMvc.perform(post("/user/add"));
(2)配置请求:设置请求参数、请求体、请求头
根据接口类型,配置请求的参数、请求体、请求头等,覆盖所有常见场景:
go
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.http.MediaType.*;
// 1. GET 请求:传递路径参数 + 请求参数 + 请求头
mockMvc.perform(get("/user/{id}", 1) // 路径参数({id} 对应后面的 1)
.param("type", "1") // 请求参数(?type=1)
.header("token", "test-token-123") // 请求头
.cookie(new Cookie("userId", "123"))); // Cookie
// 2. POST 请求:传递 JSON 请求体 + 请求头
mockMvc.perform(post("/user/add")
.contentType(APPLICATION_JSON) // 设置请求类型为 JSON
.accept(APPLICATION_JSON) // 设置接收的响应类型为 JSON
.content("{\"username\":\"测试用户\",\"age\":25}")); // JSON 请求体
// 3. POST 请求:传递表单参数
mockMvc.perform(post("/user/login")
.contentType(APPLICATION_FORM_URLENCODED) // 表单类型
.param("username", "admin")
.param("password", "123456"));
// 4. 上传文件(配合手动构建 MockMvc 时的 addFileUpload)
mockMvc.perform(multipart("/user/upload")
.file("file", "test content".getBytes())
.param("desc", "测试文件"));
(3)校验响应:andExpect()
最核心的方法,用于校验响应结果,可校验状态码、响应体、响应头、Cookie 等,常用的校验器由 MockMvcResultMatchers 提供。
go
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
mockMvc.perform(get("/user/1"))
// 1. 校验响应状态码(200 成功、404 不存在、500 服务器错误等)
.andExpect(status().isOk()) // 等价于 status().is(200)
// 2. 校验响应头
.andExpect(header().string("Content-Type", "application/json"))
// 3. 校验 Cookie
.andExpect(cookie().value("userId", "123"))
// 4. 校验响应体(JSON 格式)
.andExpect(jsonPath("$.id").value(1)) // 校验 JSON 字段 id = 1
.andExpect(jsonPath("$.username").value("测试用户")) // 校验 username
.andExpect(jsonPath("$.age").isNumber()) // 校验 age 是数字
// 5. 校验响应体(普通文本格式)
// .andExpect(content().string("操作成功"))
;
注意:jsonPath 表达式的用法和前端的 JSONPath 一致,比如 $.data.list 表示响应体中 data 对象下的 list 数组,非常灵活。
(4)辅助方法:andDo()、andReturn()
除了校验,还有两个常用辅助方法,用于调试和获取响应结果:
go
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
// 1. andDo(print()):打印完整的请求/响应日志(调试必备)
mockMvc.perform(get("/user/1"))
.andDo(print()) // 打印请求地址、请求头、响应体等信息
.andExpect(status().isOk());
// 2. andReturn():获取响应结果,用于后续自定义校验
MvcResult mvcResult = mockMvc.perform(get("/user/1"))
.andExpect(status().isOk())
.andReturn();
// 获取响应体字符串
String responseBody = mvcResult.getResponse().getContentAsString();
// 自定义校验(比如解析 JSON 后校验复杂逻辑)
User user = new ObjectMapper().readValue(responseBody, User.class);
Assertions.assertEquals(25, user.getAge());
4.3 实战场景:覆盖 90% 的接口测试需求
结合实际开发中的接口类型,分享 4 个高频实战场景,代码可直接复制到项目中修改使用。
场景1:测试 GET 接口(路径参数 + 请求参数)
假设我们有一个用户列表接口,支持分页查询,路径:/user/list,参数:pageNum(页码)、pageSize(每页条数),返回分页结果。
go
@Test
public void testUserList() throws Exception {
mockMvc.perform(get("/user/list")
.param("pageNum", "1")
.param("pageSize", "10")
.header("token", "test-token"))
.andDo(print())
.andExpect(status().isOk())
// 校验分页结果的核心字段
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.message").value("success"))
.andExpect(jsonPath("$.data.list").isArray()) // list 是数组
.andExpect(jsonPath("$.data.pageNum").value(1))
.andExpect(jsonPath("$.data.pageSize").value(10));
}
场景2:测试 POST JSON 接口(请求体 + 异常校验)
假设我们有一个添加用户接口,路径:/user/add,请求体是 JSON,要求 username 不能为空、age 必须大于 0,否则返回 400 错误。
go
@Test
public void testAddUser_Success() throws Exception {
// 构建合法的 JSON 请求体
User user = new User(null, "新用户", 22, "13800138000");
String json = new ObjectMapper().writeValueAsString(user);
mockMvc.perform(post("/user/add")
.contentType(APPLICATION_JSON)
.content(json))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.message").value("添加成功"));
}
// 测试异常场景:username 为空
@Test
public void testAddUser_Error_UsernameNull() throws Exception {
User user = new User(null, "", 22, "13800138000");
String json = new ObjectMapper().writeValueAsString(user);
mockMvc.perform(post("/user/add")
.contentType(APPLICATION_JSON)
.content(json))
.andDo(print())
.andExpect(status().isBadRequest()) // 400 错误
.andExpect(jsonPath("$.code").value(400))
.andExpect(jsonPath("$.message").contains("username 不能为空"));
}
场景3:测试拦截器(验证 token 有效性)
假设项目中有一个登录拦截器,未携带 token 或 token 无效时,拦截请求并返回 401 错误。
go
// 测试:未携带 token,被拦截
@Test
public void testWithoutToken() throws Exception {
mockMvc.perform(get("/user/1"))
.andDo(print())
.andExpect(status().isUnauthorized()) // 401 未授权
.andExpect(jsonPath("$.code").value(401))
.andExpect(jsonPath("$.message").value("请先登录"));
}
// 测试:携带无效 token,被拦截
@Test
public void testInvalidToken() throws Exception {
mockMvc.perform(get("/user/1")
.header("token", "invalid-token"))
.andDo(print())
.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.message").value("token 无效"));
}
场景4:测试文件上传接口
假设我们有一个文件上传接口,路径:/user/upload,接收文件和描述参数,返回上传结果。
go
@Test
public void testFileUpload() throws Exception {
// 构建模拟文件
MockMultipartFile file = new MockMultipartFile(
"file", // 表单字段名
"test.jpg", // 文件名
"image/jpeg", // 文件类型
"test image content".getBytes() // 文件内容
);
mockMvc.perform(multipart("/user/upload")
.file(file)
.param("desc", "测试图片"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.filename").value("test.jpg"));
}
五、@SpringBootTest + MockMvc 组合
实际开发中,我们不会单独使用 @SpringBootTest 或 MockMvc,而是将两者组合,实现「启动完整上下文 + 模拟接口请求 + 校验业务逻辑」的全链路测试,覆盖 Controller → Service → Mapper → 数据库的完整流程。
5.1 完整测试类示例
go
import com.fasterxml.jackson.databind.ObjectMapper;
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.http.MediaType;
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.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest // 启动完整上下文
@AutoConfigureMockMvc // 自动配置 MockMvc
public class UserFullLinkIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserService userService;
@Autowired
private UserMapper userMapper;
@Autowired
private ObjectMapper objectMapper;
/**
* 全链路测试:接口请求 → Service 处理 → Mapper 操作数据库 → 响应结果
*/
@Test
public void testUserFullLink() throws Exception {
// 第一步:插入测试数据(模拟数据库已有数据)
User testUser = new User(null, "全链路测试用户", 30, "13900139000");
userMapper.insert(testUser);
Long userId = testUser.getId();
// 第二步:用 MockMvc 模拟接口请求
mockMvc.perform(get("/user/{id}", userId)
.header("token", "test-token-123"))
.andDo(print())
// 第三步:校验接口响应
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(userId))
.andExpect(jsonPath("$.username").value("全链路测试用户"))
.andExpect(jsonPath("$.age").value(30));
// 第四步:校验 Service 层逻辑(确保上下文加载正常,Bean 注入有效)
User serviceUser = userService.getUserById(userId);
assertNotNull(serviceUser);
assertEquals("全链路测试用户", serviceUser.getUsername());
// 第五步:清理测试数据(避免污染数据库)
userMapper.deleteById(userId);
}
}
5.2 测试数据隔离
上面的示例中,我们手动插入和删除测试数据,虽然能实现隔离,但比较繁琐。实际开发中,推荐使用 @Transactional 注解,让测试方法执行完自动回滚数据,无需手动清理。
go
// 添加 @Transactional 注解,测试结束后自动回滚所有数据库操作
@Test
@Transactional
public void testWithTransaction() throws Exception {
// 插入测试数据
User testUser = new User(null, "事务测试用户", 28, "13700137000");
userMapper.insert(testUser);
Long userId = testUser.getId();
// 接口请求 + 校验
mockMvc.perform(get("/user/{id}", userId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("事务测试用户"));
// 无需手动删除,测试结束后自动回滚
}
注意:@Transactional 注解仅对数据库操作有效,若测试中调用了第三方接口(如支付、短信),不会回滚第三方接口的操作,需手动模拟或清理。
六、注意事项
很多开发者写集成测试时,会遇到各种奇奇怪怪的问题,整理了 10 个高频坑点,帮你少走弯路:
-
- @SpringBootTest 启动慢 → 原因:加载了完整上下文,若项目较大,启动时间会很长。解决方案:按需加载上下文,用 @TestConfiguration 自定义测试配置,只加载需要的 Bean;
-
- MockMvc 报错 404 → 原因:1. 接口路径写错(注意是否有前缀,如 /api/user);2. Controller 未被扫描到(包路径不一致);3. 未添加 @AutoConfigureMockMvc 注解;
-
- 注入 Bean 失败(报 NoSuchBeanDefinitionException) → 原因:@SpringBootTest 未找到启动类,或 Bean 未加 @Service/@Controller/@Repository 注解;
-
- 测试数据污染数据库 → 解决方案:添加 @Transactional 注解自动回滚,或使用 TestContainers 启动临时数据库;
-
- MockMvc 无法模拟文件上传 → 原因:未用 multipart() 方法,或未手动构建 MockMvc 并添加文件上传配置;
-
- jsonPath 校验报错(Invalid JSON expression) → 原因:JSON 路径写错,或响应体不是 JSON 格式(检查请求头 Content-Type 是否为 application/json);
-
- @LocalServerPort 注入失败 → 原因:未设置 webEnvironment = WebEnvironment.RANDOM_PORT/DEFINED_PORT,只有启动真实服务器时才能注入端口;
-
- 测试方法执行顺序混乱 → 原因:JUnit 5 默认随机执行测试方法。解决方案:用 @Order 注解指定执行顺序;
-
- 依赖第三方接口的测试不稳定 → 解决方案:用 Mockito 模拟第三方接口的返回,避免依赖真实第三方服务;
-
- 集成测试和单元测试混写 → 建议:分开写,单元测试放在 service/test 下,集成测试放在 controller/test 下,命名规范(如 XxxServiceTest、XxxControllerIntegrationTest)。
七、让集成测试更高效
除了基础用法,分享 3 个优化技巧,让你的集成测试更高效、更易维护:
7.1 静态导入简化代码
将 MockMvc 的常用方法静态导入,避免重复写全类名,代码更简洁:
go
// 静态导入(放在类顶部)
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
// 简化后代码
mockMvc.perform(get("/user/1"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1));
7.2 抽取测试基类
如果多个测试类都需要注入 MockMvc、ObjectMapper 等,可抽取一个测试基类,避免重复代码:
go
// 测试基类
@SpringBootTest
@AutoConfigureMockMvc
public class BaseIntegrationTest {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper;
// 可添加通用方法,如构建 JSON 请求体
protected String toJson(Object obj) throws JsonProcessingException {
return objectMapper.writeValueAsString(obj);
}
}
// 其他测试类继承基类
public class UserControllerTest extends BaseIntegrationTest {
@Test
public void testUser() throws Exception {
User user = new User(null, "测试", 25);
mockMvc.perform(post("/user/add")
.contentType(APPLICATION_JSON)
.content(toJson(user)))
.andExpect(status().isOk());
}
}
7.3 用 TestContainers 启动临时数据库
如果测试需要操作数据库,而本地数据库环境不一致,可使用 TestContainers 启动一个临时的 MySQL/PostgreSQL 容器,测试结束后自动销毁,避免环境依赖。(需添加对应依赖,这里不展开,感兴趣可留言)
八、总结
SpringBoot 集成测试的核心,就是用 @SpringBootTest 加载完整上下文,用 MockMvc 模拟 HTTP 请求,两者组合,实现接口全链路的验证。
最后再梳理核心要点,帮你快速记忆:
集成测试不是额外的负担,而是提前发现问题的重要手段。掌握 @SpringBootTest 和 MockMvc 的用法,能让你在开发中更有底气,上线更安心。
如果觉得本文对你有帮助,欢迎点赞、在看、转发,关注我,持续分享 Java 实战干货~