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?
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.
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.
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.
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.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With