2012-12-03 115 views
15

我在3.1版本中使用新的spring-test來運行集成測試。它工作得很好,但我無法讓會話正常工作。我的代碼:支持會話支持的Spring mvc 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()); 
    } 
} 

我的會話在每個請求中都是空的,我不知道爲什麼。

編輯:最後斷言失敗:andExpect(status().isOk());。它返回403而不是200.

+0

哪個斷言失敗? –

+0

最後一個:'andExpect(status()。isOk());'因爲我檢查會話中應該設置的變量,但會話是空的,所以它返回禁止。 – islon

+0

另請參見[如何使用spring 3.2新的mvc測試登錄用戶](http://stackoverflow.com/questions/14308341/how-to-login-a-user-with-spring-3-2-new-mvc -testing)。 – Arjan

回答

9

我已經在一個有點迂迴的方式做到了這一點 - 工作雖然。我所做的就是讓Spring的安全創建一個會話與填充在會話相關的安全屬性,然後抓住這屆這樣:

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

} 

有了這些小號et,現在你可以簡單地從sessionHolder中獲取會話並執行後續的方法,例如。在我的情況:

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

謝謝,它的工作原理! – islon

21

修訂答:

這似乎是一個新的方法 「sessionAttrs」 已經被添加到Builder(見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答:

這裏是一個簡單的解決方案來實現相同的結果,而不使用支持類,這是我的代碼片段(我不知道這些方法是否已經可用,當B iju 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")); 
 
+1

這絕對應該是被接受的答案!目前接受的答案是實現這一點非常骯髒的黑客。 –

+0

它真的是更好的解決方案http://stackoverflow.com/a/26341909/2674303 – gstackoverflow

+0

我遇到了一個問題,實施此解決方案。我得到以下異常'NestedServletException:請求處理失敗;嵌套異常是java.lang.ArrayIndexOutOfBoundsException:-1'。任何想法可能會導致它? – JackB