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

OncePerRequestFilter测试中Mockito指定的Mock类调用时为null如何解决?

问题根因

mock对象不生效的核心原因有两个:

  1. 你的OriginFilter使用字段注入(@Autowired直接标注私有成员变量),没有提供可传入依赖的构造方法或setter方法。测试时你是手动new OriginFilter()创建的实例,脱离了Spring容器环境,没有逻辑帮你把mock好的tokenStore注入到新建的filter实例中,所以filter里的tokenStore自然为null。
  2. 你当前的测试用例没有给mock请求设置Authorization请求头,即使注入成功也不会走到tokenStore的验证逻辑分支,只会触发Token is null的警告日志。

解决方案

方案1(推荐):修改过滤器为构造函数注入

Spring官方更推荐构造函数注入的写法,既保证依赖不可变,也天然支持单元测试传参:

@Component
public class OriginFilter extends OncePerRequestFilter {

    private final CustomJdbcTokenStore tokenStore;

    // Spring 4.3+ 单构造函数可省略@Autowired注解
    public OriginFilter(CustomJdbcTokenStore tokenStore) {
        this.tokenStore = tokenStore;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain)
            throws ServletException, IOException {
        // 原有逻辑保持不变
        final String requestTokenHeader = httpServletRequest.getHeader("Authorization");
        
        if (requestTokenHeader != null) {
            if(tokenStore.verifyUserAgentAndHostname(requestTokenHeader.substring(7), httpServletRequest.getHeader("User-Agent"), httpServletRequest.getRemoteAddr())){
                filterChain.doFilter(httpServletRequest, httpServletResponse);
            }else {
                httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            }
        } else {
            logger.warn("Token is null");
        }
    }
}

测试时直接将mock好的tokenStore传入构造函数即可:

// 测试类中创建filter实例的代码改为
OriginFilter filter = new OriginFilter(tokenStore);
// 补充添加Authorization头的逻辑,才能走到验证分支
mockRequest.addHeader("Authorization", "Bearer test_token_value");

方案2:使用Mockito的@InjectMocks注解快速注入

如果你不想修改原有过滤器的注入写法,可以直接修改测试代码,用Mockito的注入能力自动把mock对象塞到filter的私有字段里:

@RunWith(MockitoJUnitRunner.class)
public class OFilterTest {

    @Mock
    CustomJdbcTokenStore tokenStore;

    // 新增该注解,Mockito会自动把@Mock标注的对象注入到对应字段
    @InjectMocks
    private OriginFilter filter;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void CheckIfFilterPreventsDifferentOriginAccess() throws IOException, ServletException, ParseException {
        Assert.assertNotNull(tokenStore);
        // 不需要手动new OriginFilter了,直接用上面注解注入的filter实例
        MockHttpServletRequest mockRequest = new MockHttpServletRequest();
        // 补充加请求头,才能走到验证逻辑
        mockRequest.addHeader("Authorization", "Bearer test_token_value");
        MockHttpServletResponse mockResponse = new MockHttpServletResponse();
        FilterChain mockFilterChain = Mockito.mock(FilterChain.class);

        when(tokenStore.verifyUserAgentAndHostname(any(),any(),any())).thenReturn(true);

        filter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
        filter.destroy();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 02:42:02