Question

I'm using EasyMock (3.2). I want to write a test for part of my security system based on Spring Security. I want to mock the Authentication so that it returns empty list of authorities. Its method declaration is as follows:

 Collection<? extends GrantedAuthority> getAuthorities();

So I write a test:

Authentication authentication = createMock(Authentication.class);
Collection<? extends GrantedAuthority> authorities = Collections.emptyList();
expect(authentication.getAuthorities()).andReturn(authorities);

But the compiler is complaining about the third line on andReturn call:

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>

What am I doing wrong?


UPDATE:

When I change the declaration of authorities to:

Collection<GrantedAuthority> authorities = Collections.emptyList();

as suggested, it still does not compile, but the error is a bit different:

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>)

I ensured that the GrantedAuthority is actually the same in both declarations - org.springframework.security.core.GrantedAuthority.

Was it helpful?

Solution

Remove the item type from the collection declaration, you'll get a warning but the test will work.

@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);
    }

OTHER TIPS

There is no easy way you can test this function using any mocking framework. I am afraid you may have to resort to type casting. The reason being generics are skin deep when it comes to wildcards - i.e. you can specify wildcards only at the top level. So, EasyMock or any mocking framework, cannot effectively create a mock object of something which has a wildcard in it. If you look at the message:

 IExpectationSetters<Collection<? extends GrantedAuthority>>

is two level deep and that is why compiler gives it up.

A solution to this specific problem is to mock the AbstractAuthenticationToken class instead of the Authentication interface. The default implementation from spring overrides the getPrincipals() method and changes the returned type from Collection<? extends GrantedAuthority> to Collection<GrantedAuthority>. Working code:

AbstractAuthenticationToken authentication = createMock(AbstractAuthenticationToken.class);
Collection<GrantedAuthority> authorities = Collections.emptyList();
expect(authentication.getAuthorities()).andReturn(authorities);

However, this does not solve the problem in general.

The easiest is to resort to expectLastCall() instead:

authentication.getAuthorities();
expectLastCall().andReturn(authorities);

Let's examine both methods:

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;
}

So both methods do basically the same thing but expect(T value) forces IExpectationSetters to be of the same type as value while expectLastCall() pretty much returns everything you want.

Collection<? extends GrantedAuthority> means a Collection of some unknown class that extends GrantedAuthority. So, two separate declarations of Collection<? extends GrantedAuthority> could potentially be two different classes in regards to the wildcard. That's why the compiler complains.

You may just want Collection<GrantedAuthority>, which means a Collection of GrantedAuthority, which of course would permit any instance of GrantedAuthority or any of its subclasses to be added to the collection.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top