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

JUnit测试中如何用Mockito模拟RequestContextHolder.getRequest()避免空指针

问题原因

单元测试环境默认没有Web容器的请求上下文,RequestContextHolder 中没有绑定请求属性对象,调用 currentRequestAttributes() 就会返回空,后续调用 getRequest() 自然抛出空指针异常。

可行实现方案

方案1:手动构造Mock请求绑定到上下文(最通用)

Spring-test 模块自带了 MockHttpServletRequest 工具类,可以直接模拟请求对象,手动绑定到 RequestContextHolder 即可,步骤如下:

  • 第一步:单元测试类引入Spring-test依赖(一般SpringBoot项目默认已集成测试启动器,无需额外引入)
  • 第二步:在测试用例执行前初始化Mock请求并绑定上下文,测试执行后清理上下文,避免污染其他用例。

示例代码:

import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

// 你的测试类
public class CacheLookupPollingDarwinTest {

    @BeforeEach
    void initMockRequest() {
        // 构造模拟请求
        MockHttpServletRequest mockRequest = new MockHttpServletRequest();
        // 按需设置请求的参数、Header、属性等,匹配业务逻辑需要的字段
        mockRequest.addHeader("Content-Type", "application/json");
        mockRequest.setParameter("bizId", "test123");
        // 绑定到请求上下文
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest));
    }

    @AfterEach
    void clearRequestContext() {
        // 清理上下文,避免影响其他测试用例
        RequestContextHolder.resetRequestAttributes();
    }

    // 你的测试用例
    @Test
    void testCacheLookupPolling() {
        // 这里执行你的业务测试逻辑即可,不会再出现空指针
        CacheLookupPolling_Darwin fragment = beanFactory.getBean(CacheLookupPolling_Darwin.class);
        String result = fragment.cacheLookupPolling_Darwin("testParam", httpHeaders);
        // 断言结果
    }
}

方案2:纯单元测试跳过上下文获取逻辑

如果你不需要启动Spring上下文,做纯粹的单元测试,可以直接通过反射给CacheLookupPolling_Darwin类的Request成员变量赋值模拟对象,跳过从RequestContextHolder取请求的逻辑:

示例代码:

import org.springframework.mock.web.MockHttpServletRequest;
import java.lang.reflect.Field;
import org.junit.jupiter.api.Test;

@Test
void testPureUnit() throws Exception {
    CacheLookupPolling_Darwin bean = new CacheLookupPolling_Darwin();
    MockHttpServletRequest mockRequest = new MockHttpServletRequest();
    // 按需设置mockRequest的字段
    mockRequest.addHeader("your-header", "test-value");
    
    // 反射给私有成员变量赋值
    Field requestField = CacheLookupPolling_Darwin.class.getDeclaredField("Request");
    requestField.setAccessible(true);
    requestField.set(bean, mockRequest);
    
    // 执行业务逻辑测试
}
额外优化建议

你当前把DefaultHttpServletRequest作为CacheLookupPolling_Darwin类的成员变量,如果这个类是Spring默认的单例Bean,会存在严重的线程安全问题:多个请求线程会覆盖同一个Request变量,导致并发场景下请求数据混乱,建议改成方法内部局部变量,或者把类的作用域改成@RequestScope。

内容的提问来源于stack exchange,提问作者user12505474

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 17:15:02