2012-12-03 71 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