我正在使用EasyMock(3.2)。我想基于Spring Security为我的部分安全系统编写一个测试。我想模仿Authentication
,以便它返回空的权限列表。其方法声明如下:
Collection<? extends GrantedAuthority> getAuthorities();
所以我写了一个测试:
Authentication authentication = createMock(Authentication.class);
Collection<? extends GrantedAuthority> authorities = Collections.emptyList();
expect(authentication.getAuthorities()).andReturn(authorities);
但是编译器抱怨andReturn
调用的第三行:
The method andReturn(Collection<capture#1-of ? extends GrantedAuthority>) in the type IExpectationSetters<Collection<capture#1-of ? extends GrantedAuthority>> is not applicable for the arguments (Collection<capture#2-of ? extends GrantedAuthority>
我做错了什么?
更新:
当我将authorities
的声明更改为:
Collection<GrantedAuthority> authorities = Collections.emptyList();
按照建议,它仍然无法编译,但错误有点不同:
The method andReturn(Collection<capture#1-of ? extends GrantedAuthority>) in the type IExpectationSetters<Collection<capture#1-of ? extends GrantedAuthority>> is not applicable for the arguments (Collection<GrantedAuthority>)
我确保GrantedAuthority
在两个声明中实际上都是相同的 - org.springframework.security.core.GrantedAuthority
。
答案 0 :(得分:6)
从集合声明中删除项目类型,您将收到警告但测试仍然有效。
@Test
public void testFoo()
{
// setup
Authentication mockAuthentication = createMock(Authentication.class);
Collection authorities = Collections.emptyList();
expect(mockAuthentication.getAuthorities()).andReturn(authorities);
// exercise
EasyMock.replay(mockAuthentication);
Collection<? extends GrantedAuthority> retAuth = mockAuthentication.getAuthorities();
// verify
EasyMock.verify(mockAuthentication);
assertEquals(authorities, retAuth);
}
答案 1 :(得分:2)
没有简单的方法可以使用任何模拟框架测试此功能。恐怕你可能不得不求助于铸造。对于通配符而言,泛型的原因是皮肤深层 - 即您只能在顶层指定通配符。因此,EasyMock或任何模拟框架都无法有效地创建一个带有通配符的模拟对象。 如果你看一下这条消息:
IExpectationSetters<Collection<? extends GrantedAuthority>>
是两级深度,这就是编译器放弃它的原因。
答案 2 :(得分:1)
最简单的方法是改为使用expectLastCall()
:
authentication.getAuthorities();
expectLastCall().andReturn(authorities);
让我们检查两种方法:
public static <T> IExpectationSetters<T> expect(final T value) {
return getControlForLastCall();
}
public static <T> IExpectationSetters<T> expectLastCall() {
return getControlForLastCall();
}
@SuppressWarnings("unchecked")
private static <T> IExpectationSetters<T> getControlForLastCall() {
// snip
return (IExpectationSetters<T>) lastControl;
}
因此,两种方法的基本相同,但expect(T value)
强制IExpectationSetters
与value
的类型相同,而expectLastCall()
几乎可以返回您想要的所有内容。
答案 3 :(得分:0)
Collection<? extends GrantedAuthority>
表示扩展Collection
的某些未知类的GrantedAuthority
。因此,对于通配符,Collection<? extends GrantedAuthority>
的两个单独声明可能是两个不同的类。这就是编译器抱怨的原因。
您可能只需要Collection<GrantedAuthority>
,这意味着Collection
GrantedAuthority
,这当然会允许添加GrantedAuthority
或其任何子类的任何实例集合。
答案 4 :(得分:0)
此特定问题的解决方案是模拟AbstractAuthenticationToken
类而不是Authentication
接口。 spring中的默认实现会覆盖getPrincipals()
方法,并将返回的类型从Collection<? extends GrantedAuthority>
更改为Collection<GrantedAuthority>
。工作代码:
AbstractAuthenticationToken authentication = createMock(AbstractAuthenticationToken.class);
Collection<GrantedAuthority> authorities = Collections.emptyList();
expect(authentication.getAuthorities()).andReturn(authorities);
然而,这并不能解决一般问题。