Warm tip: This article is reproduced from stackoverflow.com, please click
spring-boot integration-testing mockmvc

Testing Spring Security protected Controllers with MockMvc possible?

发布于 2020-03-29 20:58:09

I'm trying to figure out, what is the best way to Test the Security configuration of my Spring Boot App. My Goal is to have two Tests:

  • Given User A, Access to Ressource /test results in 401
  • Given User B, Access to Ressource /test results in 200

When starting my Research, all Tutorials that I found pointed to "MockMvc", but I wasn't able to write 2 Tests which worked this way. In almost all cases it seemed to me like Security was completely ignored (MockMvc returned 200 even without any User given).

Lets say I have the following setup, as a simple example:

Security config:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

}

Controller:

@RestController
public class TestController {

    @GetMapping("/test")
    public String getTest() {
        return "hello";
    }

}

Properties:

spring.security.user.name=testuser
spring.security.user.password=testpassword

I could successfully test this using "TestRestTemplate" like this:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    void when_userIsValid_should_return200() throws Exception {
        String res = testRestTemplate
                .withBasicAuth("testuser", "testpassword")
                .getForEntity("/test", String.class)
                .getBody();
        Assert.assertEquals("hello", res);
    }

    @Test
    void when_userIsInvalid_should_return401() throws Exception {
        HttpStatus res = testRestTemplate
                .withBasicAuth("foo", "bar")
                .getForEntity("/test", String.class)
                .getStatusCode();
        Assert.assertEquals(HttpStatus.UNAUTHORIZED, res);
    }

}

So my question is: is this the "way to go"? If MockMvc is the Tool of choice, can you please provide a working example? I have tried like 30 solutions from Tutorials and Stackoverflow and none did work (either MockMvc null, Security was completely ignored, Controller Method wasn't detected anymore, and I'm just too stupid to make them work :/ )

Thank you in advance!

Questioner
andreas
Viewed
99
Beppe C 2020-01-31 22:22

you can use WebMvcTest to init only the Controller layer (it wont create/inject all other Spring beans defined a service/repository, etc..) but it is suitable (and quicker) when testing the Controller logic.

Here is an example

@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = MainController.class)
public class ControllerTest  {

@Autowired
private MockMvc mockMvc;

//@MockBean
//Service service; // mock service dependencies if needed

@Test
public void invalidCredentials() throws Exception {

    this.mockMvc
            .perform(get("/test").header(HttpHeaders.AUTHORIZATION,
                    "Basic " + Base64Utils.encodeToString("testuser:WRONGpassword".getBytes())))
            .andExpect(status().isOk());
}