Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Spring MockMvc result not contain a cookie?

I am trying to unit-test login and security in my REST API, so I try to mock real-life request sequences as close as possible.

My first request would be:

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).
    addFilters(springSecurityFilterChain).build();
this.mapper = new ObjectMapper();
....
MvcResult result=mockMvc.perform(get("/login/csrf")).andExpect(status().is(200)).andReturn();
Cookie[] cookies = result.getResponse().getCookies();

(See full class on pastebin).

I try to get the cookie here to be able to login with the received CSRF token later, but the cookies array is empty!

However, if I run my application and call

curl -i http://localhost:8080/login/csrf

I do get back a Set-Cookie header and can use that cookie (and the CSRF token) later to authenticate.

So the question is: How do I get MockMvc to return a cookie to me?

like image 682
P.Péter Avatar asked Oct 01 '14 13:10

P.Péter


People also ask

How does MockMvc perform work?

MockMVC class is part of Spring MVC test framework which helps in testing the controllers explicitly starting a Servlet container. In this MockMVC tutorial, we will use it along with Spring boot's WebMvcTest class to execute Junit testcases which tests REST controller methods written for Spring boot 2 hateoas example.

Is MockMvc thread safe?

From a technical point of view MockMvc is not thread-safe and shouldn't be reused. These setters are package private and a MockMvc instance can be acquired only through MockMvcBuilders . Hence you can't manipulte a MockMvc instance afterwards so that it is actually resuable across multiple tests.

Does spring session use cookies?

This guide describes how to configure Spring Session to use custom cookies with Java Configuration. The guide assumes you have already set up Spring Session in your project using your chosen data store.


2 Answers

I have found a workaround, using the ability to directly extract session objects from the MockHttpServletRequest:

session=(MockHttpSession)result.getRequest().getSession();

And later inserting the session directly:

req.session(session);

The reason why I am not pleased with this solution is that if the mock httpservlet behaves differently than the real servlet in this regard, how can I be sure whether it behaves the same as the real servlet in other cases. So I am not testing the application itself, which potentially leaves gaps in the tests.

like image 116
P.Péter Avatar answered Oct 16 '22 06:10

P.Péter


I work with RestTemplate for testing with cookies. RestTemplate cookies handler

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Import(RestTemplateWithCookies.class)
public class ApplicationTest {

    @LocalServerPort
    private int port;

    @Autowired
    private Environment env;

    @Autowired
    private RestTemplateWithCookies restTemplate;

    @Test
    public void appTest() throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Referer", env.getProperty("allowed_referer"));
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange("http://localhost:" + port + "/[email protected]", HttpMethod.GET, entity, String.class);
        assertTrue(response.getStatusCode() == HttpStatus.FOUND);
        HttpCookie c = restTemplate.getCoookies().stream().filter(x -> env.getProperty("server.session.cookie.name").equals(x.getName())).findAny().orElse(null);
        assertTrue(c != null);

    }

}
like image 28
GerardNorton Avatar answered Oct 16 '22 06:10

GerardNorton