【问题标题】:Spring mvc 3.1 integration tests with session support具有会话支持的 Spring mvc 3.1 集成测试
【发布时间】:2012-12-03 16:01:37
【问题描述】:

我正在使用 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。

【问题讨论】:

标签: java spring testing spring-mvc


【解决方案1】:

更新答案:

似乎在构建器中添加了一个新方法“sessionAttrs”(参见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());

旧答案:

这是一个更简单的解决方案,可以在不使用支持类的情况下达到相同的结果,这是我的代码的 sn-p(我不知道当 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"));

【讨论】:

  • 这绝对应该是公认的答案!当前接受的答案是实现这一目标的非常肮脏的技巧。
  • 我在实施此解决方案时遇到了问题。我收到以下异常NestedServletException: Request processing failed; nested exception is java.lang.ArrayIndexOutOfBoundsException: -1。知道是什么原因造成的吗?
【解决方案2】:

我以一种有点迂回的方式做到了这一点——虽然有效。我所做的是让 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扩展而来的另一个类,只是因为session方法需要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")));

【讨论】:

    猜你喜欢
    • 2015-09-23
    • 2015-02-13
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 2017-06-09
    • 2019-05-08
    • 1970-01-01
    • 2015-03-24
    相关资源
    最近更新 更多