Spring mvc 3.1集成测试,支持会话

我正在使用3.1版本中的新spring-test来运行集成测试。 它工作得很好,但我不能使会话工作。 我的代码:

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration("src/main/webapp") @ContextConfiguration({"classpath:applicationContext-dataSource.xml", "classpath:applicationContext.xml", "classpath:applicationContext-security-roles.xml", "classpath:applicationContext-security-web.xml", "classpath:applicationContext-web.xml"}) public class SpringTestBase { @Autowired private WebApplicationContext wac; @Autowired private FilterChainProxy springSecurityFilterChain; @Autowired private SessionFactory sessionFactory; protected MockMvc mock; protected MockHttpSession mockSession; @Before public void setUp() throws Exception { initDataSources("dataSource.properties"); mock = MockMvcBuilders.webAppContextSetup(wac).addFilters(springSecurityFilterChain).build(); mockSession = new MockHttpSession(wac.getServletContext(), UUID.randomUUID().toString()); } @Test public void testLogin() throws Exception { // this controller sets a variable in the session mock.perform(get("/") .session(mockSession)) .andExpect(model().attributeExists("csrf")); // I set another variable here just to be sure mockSession.setAttribute(CSRFHandlerInterceptor.CSRF, csrf); // this call returns 403 instead of 200 because the session is empty... mock.perform(post("/setup/language") .session(mockSession) .param(CSRFHandlerInterceptor.CSRF, csrf) .param("language", "de")) .andExpect(status().isOk()); } } 

我的会话在每个请求中都是空的,我不知道为什么。

编辑:最后一个断言失败: andExpect(status().isOk()); 。 它返回403而不是200。

我以一种有点迂回的方式做到了这一点 – 尽管如此。 我所做的是让Spring-Security创建一个会话,其中包含会话中填充的相关安全属性,然后以这种方式获取该会话:

  this.mockMvc.perform(post("/j_spring_security_check") .param("j_username", "fred") .param("j_password", "fredspassword")) .andExpect(status().isMovedTemporarily()) .andDo(new ResultHandler() { @Override public void handle(MvcResult result) throws Exception { sessionHolder.setSession(new SessionWrapper(result.getRequest().getSession())); } }); 

SessionHolder是我的自定义类,只是为了保存会话:

 private static final class SessionHolder{ private SessionWrapper session; public SessionWrapper getSession() { return session; } public void setSession(SessionWrapper session) { this.session = session; } } 

而SessionWrapper是从MockHttpSession扩展的另一个类,因为会话方法需要MockHttpSession:

 private static class SessionWrapper extends MockHttpSession{ private final HttpSession httpSession; public SessionWrapper(HttpSession httpSession){ this.httpSession = httpSession; } @Override public Object getAttribute(String name) { return this.httpSession.getAttribute(name); } } 

有了这些设置,现在您可以简单地从sessionHolder中获取会话并执行后续方法,例如。 在我的情况下:

 mockMvc.perform(get("/membersjson/1").contentType(MediaType.APPLICATION_JSON).session(sessionHolder.getSession())) .andExpect(status().isOk()) .andExpect(content().string(containsString("OneUpdated"))); 

更新的答案:

似乎新的方法“sessionAttrs”已添加到构建器中(请参阅带有session属性的mvc控制器测试 )

 Map sessionAttrs = new HashMap<>(); sessionAttrs.put("sessionAttrName", "sessionAttrValue"); mockMvc.perform(MockMvcRequestBuilders.get("/uri").sessionAttrs(sessionAttrs)) .andDo(print()) .andExpect(MockMvcResultMatchers.status().isOk()); 

老答案:

这是一个更简单的解决方案,可以在不使用支持类的情况下获得相同的结果,这是我的代码片段(我不知道这些方法在Biju Kunjummen回答时是否已经可用):

 HttpSession session = mockMvc.perform(post("/login-process").param("j_username", "user1").param("j_password", "user1")) .andExpect(status().is(HttpStatus.FOUND.value())) .andExpect(redirectedUrl("/")) .andReturn() .getRequest() .getSession(); Assert.assertNotNull(session); mockMvc.perform(get("/").session((MockHttpSession)session).locale(Locale.ENGLISH)) .andDo(print()) .andExpect(status().isOk()) .andExpect(view().name("logged_in"));
HttpSession session = mockMvc.perform(post("/login-process").param("j_username", "user1").param("j_password", "user1")) .andExpect(status().is(HttpStatus.FOUND.value())) .andExpect(redirectedUrl("/")) .andReturn() .getRequest() .getSession(); Assert.assertNotNull(session); mockMvc.perform(get("/").session((MockHttpSession)session).locale(Locale.ENGLISH)) .andDo(print()) .andExpect(status().isOk()) .andExpect(view().name("logged_in"));