为已运行的Spring MVC应用添加JUnit测试套件的方法咨询
为传统Spring MVC应用添加Controller API测试的步骤
1. 添加必要的测试依赖
在你的构建工具(Maven/Gradle)中加入以下核心测试库,所有依赖均为Spring生态基础组件,无Spring Boot相关内容:
- JUnit:选择JUnit 4或5(以下以JUnit 4为例,JUnit 5仅需调整注解和依赖坐标)
- Spring Test:提供MockMvc、TestContext等Web测试核心支持
- Mockito:用于Mock Controller依赖的Service/DAO层,隔离真实业务逻辑
- Jackson Databind(可选):用于JSON响应的断言处理
Maven依赖示例:
<dependencies> <!-- JUnit 4 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <!-- Spring Test(版本需与应用Spring核心版本完全一致) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>你的Spring版本号</version> <scope>test</scope> </dependency> <!-- Mockito --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> <!-- JSON处理 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> <scope>test</scope> </dependency> </dependencies>
2. 编写Controller测试类基础配置
根据测试需求选择两种配置方式:
方式一:加载完整Web上下文(适合集成测试)
使用Spring Test注解加载应用原有的Spring配置,测试真实的请求路由和上下文:
import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations = { "classpath:spring-mvc.xml", // 应用原有的MVC配置文件 "classpath:spring-service.xml" // 可选,若需加载真实Service层 }) public class UserControllerTest { @Autowired private WebApplicationContext webApplicationContext; private MockMvc mockMvc; @Before public void setup() { // 基于Web上下文构建MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } }
若应用使用JavaConfig而非XML,@ContextConfiguration可直接指定配置类:
@ContextConfiguration(classes = {WebMvcConfig.class, ServiceConfig.class})
方式二:Mock依赖+独立Controller(适合单元测试)
仅加载待测试的Controller,用MockitoMock其依赖,测试速度更快:
import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @RunWith(MockitoJUnitRunner.class) public class UserControllerTest { @Mock private UserService userService; // Controller依赖的Service @InjectMocks private UserController userController; // 待测试的Controller private MockMvc mockMvc; @Before public void setup() { // 基于独立Controller实例构建MockMvc mockMvc = MockMvcBuilders.standaloneSetup(userController).build(); } }
3. 编写具体API测试用例
使用MockMvc模拟HTTP请求,验证响应状态、内容、参数绑定等核心逻辑:
示例1:GET请求测试
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.mockito.Mockito.when; @Test public void testGetUserById() throws Exception { // 预设Mock Service的返回值 User mockUser = new User(1L, "testUser"); when(userService.getUserById(1L)).thenReturn(mockUser); // 模拟GET请求并断言响应 mockMvc.perform(get("/users/{id}", 1L) .contentType("application/json")) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1L)) .andExpect(jsonPath("$.username").value("testUser")); }
示例2:POST请求测试
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.mockito.Mockito.verify; @Test public void testCreateUser() throws Exception { User newUser = new User(null, "newUser"); User savedUser = new User(2L, "newUser"); when(userService.saveUser(newUser)).thenReturn(savedUser); // 模拟POST请求,传递JSON参数 mockMvc.perform(post("/users") .contentType("application/json") .content("{\"username\":\"newUser\"}")) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").value(2L)) .andExpect(jsonPath("$.username").value("newUser")); // 验证Mock Service方法是否被正确调用 verify(userService).saveUser(newUser); }
示例3:参数校验失败场景测试
@Test public void testCreateUserWithInvalidParam() throws Exception { // 传递空用户名,触发JSR-380校验失败 mockMvc.perform(post("/users") .contentType("application/json") .content("{\"username\":\"\"}")) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.errors[0].message").value("用户名不能为空")); }
4. 组织测试套件
将多个Controller测试类整合为一个套件,方便批量运行:
import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ UserControllerTest.class, OrderControllerTest.class, // 其他Controller测试类 }) public class ControllerTestSuite { // 无需编写业务代码,仅作为套件入口 }
5. 关键注意事项
- 版本一致性:Spring Test版本必须与应用Spring核心版本完全匹配,避免兼容性问题
- 测试隔离:每个测试方法独立,使用
@Before初始化、@After清理状态 - 避免外部依赖:测试Controller时不要依赖真实数据库、外部接口,全部用Mock替代
- 覆盖核心场景:重点测试正常流程、异常流程、参数边界、权限控制(若有)等场景
内容的提问来源于stack exchange,提问作者Giuseppe
相关产品推荐
相关产品推荐

