如何Mock Authentication.getAuthorities()?编译错误解决方法
场景背景
我实现了一个Spring OncePerRequestFilter 过滤器,核心逻辑是根据用户权限判断是否处理请求,代码如下:
过滤器核心方法
@Override protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException { final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && containsRole(auth, "SpecificRole")) { doThingsWithTheRequest(request); } filterChain.doFilter(request, response); }
权限判断方法
protected boolean containsRole(final Authentication auth, final String role) { for (final GrantedAuthority ga : auth.getAuthorities()) { if (ga.getAuthority().equals(role)) { return true; } } return false; }
为测试该逻辑,我编写了JUnit测试,尝试Mock Authentication.getAuthorities() 让权限判断返回true,但遇到编译错误:
测试代码
@Test public void test() throws ServletException, IOException, CommerceCartRestorationException { SecurityContext securityContextMock = mock(SecurityContext.class); Authentication authenticationMock = mock(Authentication.class); SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("MyRole"); Collection<SimpleGrantedAuthority> authCollection = Collections.singleton(simpleGrantedAuthority); // 此处出现编译错误 when(authenticationMock.getAuthorities()).thenReturn(authCollection); when(securityContextMock.getAuthentication()).thenReturn(authenticationMock); SecurityContextHolder.setContext(securityContextMock); testObj.doFilterInternal(httpServletRequestMock, httpServletResponseMock, filterChainMock); }
错误信息:
Cannot resolve method 'thenReturn(Collection)'
已知Authentication.getAuthorities()返回Collection<? extends GrantedAuthority>,SimpleGrantedAuthority实现了GrantedAuthority接口,且无法使用spring-security-test依赖及@WithMockUser注解。
错误原因
Mockito的when...thenReturn语法在处理带通配符的泛型(Collection<? extends GrantedAuthority>)时,无法自动完成类型推断。虽然Collection<SimpleGrantedAuthority>是Collection<? extends GrantedAuthority>的子类型,但编译器无法识别两者的兼容性,导致找不到匹配的thenReturn方法重载。
修复方案
提供三种可行的修复方式:
1. 调整集合的泛型类型
将集合的泛型声明为GrantedAuthority,使其与方法返回的泛型类型完全匹配:
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("MyRole"); Collection<GrantedAuthority> authCollection = Collections.singleton(simpleGrantedAuthority);
2. 显式指定thenReturn的泛型参数
通过泛型参数明确告知编译器返回类型,帮助完成类型推断:
when(authenticationMock.getAuthorities()).<Collection<? extends GrantedAuthority>>thenReturn(authCollection);
3. 使用doReturn语法替代
Mockito的doReturn语法对泛型的兼容性更好,可以绕过类型推断问题:
doReturn(authCollection).when(authenticationMock).getAuthorities();
内容的提问来源于stack exchange,提问作者Niklas

