2012-12-03 11 views
15

Używam nowej wersji spring-test w wersji 3.1 do przeprowadzania testów integracji. Działa bardzo dobrze, ale nie mogę sprawić, żeby sesja działała. Mój kod:Wiosenne testy integracji mvc 3.1 z obsługą sesji

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

Moja sesja jest pusta w każdym wniosku, nie wiem dlaczego.

EDYCJA: Ostatnia próba kończy się niepowodzeniem: andExpect(status().isOk());. Zwraca 403 zamiast 200.

+0

Które stwierdzenie zawodzi? –

+0

Ostatni: 'andExpect (status(). IsOk());' ponieważ sprawdzam sesję dla zmiennej, która powinna być ustawiona, ale sesja jest pusta, więc zwraca ona zabronione. – islon

+0

Zobacz także [Jak zalogować użytkownika z wiosną 3.2 nowe testy mvc] (http://stackoverflow.com/questions/14308341/how-to-login-a-user-with-spring-3-2-new-mvc testowanie). – Arjan

Odpowiedz

9

Zrobiłem to w nieco okrężny sposób - działa jednak. To, co zrobiłem było pozwolić Wiosna-Security utworzyć sesję z odpowiednimi atrybutami bezpieczeństwa zaludnionych w sesji, a następnie chwycić tej sesji w ten sposób:

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 jest mój zwyczaj klasa, po prostu trzymać sesję:

private static final class SessionHolder{ 
    private SessionWrapper session; 


    public SessionWrapper getSession() { 
     return session; 
    } 

    public void setSession(SessionWrapper session) { 
     this.session = session; 
    } 
} 

i SessionWrapper inna klasa odchodzące od MockHttpSession tylko dlatego, że sposób sesji wymaga 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); 
    } 

} 

tymi s et, teraz możesz po prostu wziąć sesję z sessionHolder i wykonać kolejne metody, na przykład. w moim przypadku:

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

Dzięki, to działa! – islon

21

AKTUALIZACJA ODPOWIEDŹ:

Wydaje nową metodę "sessionAttrs" została dodana do konstruktora (patrz mvc controller test with session attribute)

Map<String, Object> sessionAttrs = new HashMap<>(); 
sessionAttrs.put("sessionAttrName", "sessionAttrValue"); 

mockMvc.perform(MockMvcRequestBuilders.get("/uri").sessionAttrs(sessionAttrs)) 
     .andDo(print()) 
     .andExpect(MockMvcResultMatchers.status().isOk()); 

OLD odpowiedź:

tutaj jest prostsze rozwiązanie do osiągnięcia tego samego wyniku bez użycia klas pomocniczych, jest to fragment kodu (nie wiem, czy te metody były już dostępne, gdy B iju Kunjummen odpowiedział):


     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")); 
 
+1

To zdecydowanie powinna być akceptowana odpowiedź! Obecna przyjęta odpowiedź jest bardzo brudnym hackerem, aby to osiągnąć. –

+0

to jest naprawdę lepsze rozwiązanie http://stackoverflow.com/a/26341909/2674303 – gstackoverflow

+0

Mam problem z zaimplementowaniem tego rozwiązania. Otrzymuję następujący wyjątek 'NestedServletException: Przetwarzanie żądania nie powiodło się; Zagnieżdżony wyjątek to java.lang.ArrayIndexOutOfBoundsException: -1'. Masz pojęcie, co może być przyczyną? – JackB

Powiązane problemy