如何与HtmlUnit共享MockMvc会话?

时间:2015-10-01 21:48:41

标签: spring spring-mvc htmlunit spring-test geb

我正在使用Spring Test MVC HtmlUnit和Geb来为我的Spring MVC应用程序驱动功能测试。我想检查在交互过程中是否正确保存了一些会话变量。我尝试创建一个测试控制器来返回这些变量,但是HtmlUnit和mvc.perform()正在使用不同的会话。有没有办法在它们之间使用单个共享会话?

驱动程序设置:

MockMvc mvc = MockMvcBuilders.webAppContextSetup(ctx)
    .apply(SecurityMockMvcConfigurers.springSecurity())
    .build()

HtmlUnitDriver driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(mvc).javascriptEnabled(true).build()

试验:

when:
    via ProtectedPage

then:
    // this uses session A
    at LoginPage

and:
    // this uses session B
    println mvc.perform(get('/test/sessionAttributes')).andReturn().response.contentAsString

1 个答案:

答案 0 :(得分:5)

摘要

我可以问你为什么要在MockMvc中做一些你的工作,还有一些在HtmlUnit中做?它真的不是这样设计的。相反,我建议与HtmlUnit进行交互以使用会话(就像您的浏览器一样)并验证这些结果。

这不起作用的原因是MockMvc.perform孤立地工作。 HtmlUnit集成桥接MockMvc.perform调用,以确保它们在浏览器中工作(即跟踪会话)。但是,封装MockMvc.perform调用的逻辑是封装的。

MockMvc行为

MockMvc请求隔离工作,默认情况下会在每个请求上使用新会话。例如,以下两个请求对不同的会话进行操作:

// this uses session A
mvc.perform(get("/test"))

// this uses session B
mvc.perform(get("/test"))

为了重用会话,您必须从第一个MockMvc.perform调用获取会话,并在第MockMvc.perform次调用时设置它。例如:

MvcResult mvcResult = mvc
        .perform(get("/a"))
        .andReturn();

// reuse the previous session   
MockHttpSession session = (MockHttpSession) mvcResult
        .getRequest().getSession();
mvc.perform(get("/b").session(session));

HtmlUnit支持跟踪MockMvcWebConnection中的会话,并根据JSESSIONID cookie设置适当的会话(类似于您在上面看到的)。

为了在HttpSession请求中重用HtmlUnit支持中的MockMvc,您需要访问原始会话。但是,此逻辑封装在HtmlUnit支持中,因此您无法访问它。

解决方法

我不希望我们公开HtmlUnit集成的内部。我也不建议将MockMvc HtmlUnit集成与直接MockMvc用法混合和匹配。但是,您可以解决此问题。

第一步是创建一个跟踪上一个会话的ResultHandler

public class SessionTracking implements ResultHandler {
    private MockHttpSession lastSession;

    @Override
    public void handle(MvcResult result) throws Exception {
        lastSession = (MockHttpSession) result.getRequest().getSession(false);
    }

    public MockHttpSession getLastSession() {
        return lastSession;
    }
}

下一步是确保您在SessionTracking个实例中注册MockMvc

SessionTracking sessions = new SessionTracking();

MockMvc mvc = MockMvcBuilders
        .webAppContextSetup(context)
        .apply(SecurityMockMvcConfigurers.springSecurity())
        // ADD THIS
        .alwaysDo(sessions)
        .build();

HtmlUnitDriver driver = MockMvcHtmlUnitDriverBuilder
    .mockMvcSetup(mvc)
    .build();

现在,如果您需要发出MockMvc请求,则可以使用SessionTracking对象访问上一个会话。

when:
    via ProtectedPage

then:
    // this uses session A
    at LoginPage

and:
    // this uses session A
    println mvc.perform(get('/test/sessionAttributes').session(sessions.lastSession).andReturn().response.contentAsString