如何解决JUnit+Mockito测试含ServletUriComponentsBuilder的Post接口报错问题
解决"No current ServletRequestAttributes"错误的两种方案
错误原因
直接调用Controller方法时,ServletUriComponentsBuilder.fromCurrentRequest()依赖当前Servlet请求上下文,但普通单元测试(未启动Spring Web上下文)中不存在该上下文,因此抛出此错误。
方案一:使用MockMvc进行Controller测试(推荐)
这种方式更贴近真实HTTP请求场景,无需手动处理请求上下文:
测试类改造
@WebMvcTest(EventController.class) public class EventControllerTest { @Autowired private MockMvc mockMvc; @MockBean private EventJPAService eventJPAService; @Test public void testCreateEventsForUser() throws Exception { String username = "testuser"; int expectedEventId = 404; EventBean savedEvent = new EventBean(expectedEventId, username, "New Event", "Planning", LocalDate.now()); // Mock service层行为 when(eventJPAService.save(any(EventBean.class))).thenReturn(savedEvent); // 构造请求并执行 mockMvc.perform(post("/users/{username}/events", username) .contentType(MediaType.APPLICATION_JSON) .content("{\"title\":\"New Event\",\"status\":\"Planning\",\"date\":\"" + LocalDate.now() + "\"}")) // 断言响应状态 .andExpect(status().isCreated()) // 断言Location头 .andExpect(header().string("Location", endsWith("/" + expectedEventId))); } }
方案二:手动设置请求上下文(单元测试场景)
如果坚持直接调用Controller方法,需在测试中手动注入Servlet请求上下文:
修改原测试方法
@Test public void testCreateEventsForUser() { String username = "testuser"; EventBean newEvent = new EventBean(0, "", "New Event", "Planning", LocalDate.now()); int expectedEventId = 404; EventBean savedEvent = new EventBean(expectedEventId, username, "New Event", "Planning", LocalDate.now()); // 1. 手动设置Servlet请求上下文 MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/users/" + username + "/events"); ServletRequestAttributes attributes = new ServletRequestAttributes(request); RequestContextHolder.setRequestAttributes(attributes); try { // 2. Mock service层行为(用any匹配对象,避免实例不同导致Mock失效) when(eventJPAService.save(any(EventBean.class))).thenReturn(savedEvent); ResponseEntity<Object> response = eventController.createEventsForUser(username, newEvent); // 断言结果 assertEquals(201, response.getStatusCodeValue()); URI location = response.getHeaders().getLocation(); assertEquals("/users/testuser/events/404", location.getPath()); } finally { // 3. 清理请求上下文,避免影响其他测试 RequestContextHolder.resetRequestAttributes(); } }
额外注意点
- 原测试中
when(eventJPAService.save(newEvent))可能因对象实例不同导致Mock不生效,建议改用any(EventBean.class)匹配任意EventBean对象。 - 方案一中的请求JSON需根据
EventBean的字段调整,确保能正确反序列化。
内容的提问来源于stack exchange,提问作者Prathamesh Zingade
相关产品推荐
相关产品推荐

