Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MockMvc doesn't contain cookies

I have a controller protected with HTTP Basic authentication.

I setup the app to use session cookies and it works.

However when I test the controller using MockMvc, a successful authentication does not give me any cookie.

Web configuration:

package world.pyb.spring.cookiesdemo;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("argentina").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //@formatter:off
        http.httpBasic()
                .and().authorizeRequests().antMatchers(HttpMethod.GET, "/hello").authenticated()
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
        //@formatter:on
    }
}

Simple controller:

package world.pyb.spring.cookiesdemo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String index() {
        return "Greetings from Spring Boot!";
    }

}

Simple controller test that doesn't give me the session cookie:

package world.pyb.spring.cookiesdemo;

import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello")
            .with(SecurityMockMvcRequestPostProcessors.httpBasic("admin", "argentina"))
    )
        // prints "Cookies = []"
        .andDo(MockMvcResultHandlers.print())
        .andExpect(cookie().exists("JSESSIONID"))
        .andExpect(status().is2xxSuccessful())
        .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }

}

Related questions:

  • Why does Spring MockMvc result not contain a cookie?
  • Unit Testing /login in Spring MVC using MockMvc
  • Spring MVC testing (security Integration test), JSESSIONID is not present

Some answers suggest not to use MockMvc but I'd like to keep using it if possible.

like image 839
pyb Avatar asked Oct 17 '17 15:10

pyb


1 Answers

As shown in the question's code, MockMvcResultMatcher includes support for cookies.

This will work fine, as long as the controller under test itself delivers the cookie. The problem here is that the cookie is delivered by Spring Security, which is a wrapper around your controller. MockMvc is testing your controller directly, and not testing your controller running in its real HTTP server, as would be required to test the security-layer cookies.

That's why TestRestTemplate, which invokes your controller in its full server context, delivers a more thorough test environment.

Notice however that as of Spring 5, the newer approach to running-server API testing is based on WebTestClient.

like image 153
Brent Bradburn Avatar answered Nov 18 '22 02:11

Brent Bradburn