@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(value = {"classpath:/WEB-INF/Project-servlet.xml", "classpath:/WEB-INF/security.xml", "classpath:/WEB-INF/datasource.xml", "classpath:/WEB-INF/user.xml"}) public class HelloControllerTest extends AbstractJUnit4SpringContextTests { private MockMvc mockMvc; @Autowired private WebApplicationContext wac; @Autowired @Qualifier("authServiceProvider4") private UserDetailsService userDetailsService; @Autowired private FilterChainProxy proxy; @Before public void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilter(proxy).build(); } @Test public void testUserWithAdminRoleLandOnWelcomeUrl() throws Exception { UserDetails ud = userDetailsService.loadUserByUsername("user1"); Authentication auth = new UsernamePasswordAuthenticationToken(ud.getUsername(), ud.getPassword(), ud.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(auth); ... mockMvc.perform(get("/welcome")) .andExpect(status().isOk()); } }Code sample above showing a test method testing on valid user, user1, landing on welcome site which require admin role in order to render the page. Somehow the test were failed, and following failure trace were seen:
java.lang.AssertionError: Status expected:<200> but was:<302> at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60) at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89) at org.springframework.test.web.servlet.result.StatusResultMatchers$5.match(StatusResultMatchers.java:546) at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141) at org.huahsin.sit.HelloControllerTest.testUserWithAdminRoleLandOnWelcomeUrl(HelloControllerTest.java:101) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:622) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)From what I understand from this answer, the session of user1 were gone missing, I need to hold the session of user1 when MockMvc doing its work. To do this, a mocking session class is require:
public static class MockSecurityContext implements SecurityContext { private static final long serialVersionUID = -1386535243513362694L; private Authentication authentication; public MockSecurityContext(Authentication authentication) { this.authentication = authentication; } @Override public Authentication getAuthentication() { return this.authentication; } @Override public void setAuthentication(Authentication authentication) { this.authentication = authentication; } }After that create a mock session and pass it to MockMvc to perform its test work.
@Test public void testUserWithAdminRoleLandOnWelcomeUrl() throws Exception { UserDetails ud = userDetailsService.loadUserByUsername("user1"); Authentication auth = new UsernamePasswordAuthenticationToken(ud.getUsername(), ud.getPassword(), ud.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(auth); MockHttpSession session = new MockHttpSession(); session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, new MockSecurityContext(auth)); mockMvc.perform(get("/welcome").session(session)) .andExpect(status().isOk()); }