OncePerRequestFilter测试中Mockito指定的Mock类调用时为null如何解决?
问题根因
mock对象不生效的核心原因有两个:
- 你的
OriginFilter使用字段注入(@Autowired直接标注私有成员变量),没有提供可传入依赖的构造方法或setter方法。测试时你是手动new OriginFilter()创建的实例,脱离了Spring容器环境,没有逻辑帮你把mock好的tokenStore注入到新建的filter实例中,所以filter里的tokenStore自然为null。 - 你当前的测试用例没有给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
相关产品推荐
相关产品推荐

