问题
I integrated easymock with my Spring project and performed most of the unit tests. But got an issue with not able to mock the super method. When I run my test class it says method not supported.
Any idea what's going wrong as I tried my best for last couple of days and not able to get any clue on how to mock the super method.
org.springframework.security.authentication.AuthenticationServiceException: Authentication method not supported:
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:71)
at com.dashboard.core.CustomAuthenticationFilter.attemptAuthentication(CustomAuthenticationFilter.java:20)
at com.dashboard.core.CustomAuthenticationFilterTest.testAttemptAuthentication(CustomAuthenticationFilterTest.java:64)
Class which is subject to testing:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.dashboard.domain.ApplicationConstant;
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
String username = request.getParameter("j_username");
String password = request.getParameter("j_password");
if(isValidUsername(username) && isValidPassword(password) ){
return super.attemptAuthentication(request, response);
}
throw new BadCredentialsException(ApplicationConstant.CREDENTIALS_NOT_FORMAT.getValue());
}
private static boolean isValidUsername(String username){
return !StringUtils.isEmpty(username) && username.matches(ApplicationConstant.USERNAME_PATTERN.getValue());
}
private static boolean isValidPassword(String password){
return !StringUtils.isEmpty(password) && password.matches(ApplicationConstant.PWD_PATTERN.getValue());
}
}
My Test class:
import java.util.ArrayList;
import java.util.List;
import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@RunWith(EasyMockRunner.class)
public class CustomAuthenticationFilterTest extends EasyMockSupport{
@TestSubject
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter();
@Mock
UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter;
@Test
public void testAttemptAuthentication() throws Exception{
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("j_username", "Sundar1234");
request.setParameter("j_password", "Sundar1234$$");
MockHttpServletResponse response = new MockHttpServletResponse();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<SimpleGrantedAuthority> updatedAuthorities = new ArrayList<SimpleGrantedAuthority>();
updatedAuthorities.add(authority);
User user = new User("Sundar1234", "Sundar1234$$", updatedAuthorities);
Authentication auth = new UsernamePasswordAuthenticationToken(user,null);
EasyMock.expect(usernamePasswordAuthenticationFilter.attemptAuthentication(request, response)).andReturn(auth);
EasyMock.replay(usernamePasswordAuthenticationFilter);
Assert.assertNotNull(customAuthenticationFilter.attemptAuthentication(request, response));
EasyMock.verify(usernamePasswordAuthenticationFilter);
}
}
回答1:
UsernamePasswordAuthenticationFilter
is a base class, not an injected dependency. Normally, you can workaround that by using a partial mock. But you can't since CustomAuthenticationFilter
is calling super.attemptAuthentication
which can't be mocked.
Your solutions are:
- Test
CustomAuthenticationFilter
and its superclass altogether - Use a delegation pattern instead
But because of the current Spring design for such filter, delegating seems clunky. So testing altogether is I think your best bet.
来源:https://stackoverflow.com/questions/51121709/mocking-super-method-call-using-easymock-powermock