Spring mvc 3.1 интеграционные тесты с поддержкой сеанса
Я использую новый spring -test в версии 3.1 для запуска интеграционных тестов. Он работает очень хорошо, но я не могу заставить сеанс работать. Мой код:
@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());
}
}
Моя сессия пуста в каждом запросе, я не знаю почему.
EDIT: Последнее утверждение не выполняется: andExpect(status().isOk());
. Он возвращает 403 вместо 200.
Ответы
Ответ 1
Я сделал это несколько обходным путем - работает. То, что я сделал, это позволить 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")));
Ответ 2
ОБНОВЛЕННЫЙ ОТВЕТ:
Кажется, новый метод "sessionAttrs" был добавлен в конструктор (см. тест контроллера mvc с атрибутом сеанса)
Map<String, Object> sessionAttrs = new HashMap<>();
sessionAttrs.put("sessionAttrName", "sessionAttrValue");
mockMvc.perform(MockMvcRequestBuilders.get("/uri").sessionAttrs(sessionAttrs))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk());
СТАРЫЙ ОТВЕТ:
вот более простое решение для достижения того же результата без использования вспомогательных классов, это фрагмент кода (я не знаю, были ли эти методы уже доступны, когда ответил Биджу Кунджуммен):
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"));