You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:43:10