Integrating Spring Security With Spring MVC Test Framework

After we have finished this lesson, we

  • Know how we can get the required dependencies with Maven and Gradle.
  • Understand how we can integrate Spring Security with Spring MVC Test framework when we are using either Spring Framework or Spring Boot.

Getting the Required Dependencies

Before we can integrate Spring Security with Spring MVC Test framework, we have to declare the spring-security-test dependency in our build script.

If we are using Maven, we have to add the following snippet into our pom.xml file:

1<dependency>
2	<groupId>org.springframework.security</groupId>
3	<artifactId>spring-security-test</artifactId>
4	<scope>test</scope>
5	<version>4.1.4.RELEASE</version>
6</dependency>

If we are using Gradle, we have to add the following snippet into our build.gradle file:

1integrationTestCompile(
2	'org.springframework.security:spring-security-test:4.1.4.RELEASE'
3)
We must remember that the version of the spring-security-test dependency must be the same as our Spring Security version.

We can now integrate Spring Security with Spring MVC Test framework. Let’s find out how we can do it.

Configuring Our Integration Tests

Using Spring Framework

If we are using Spring Framework, we can integrate Spring Security with Spring MVC Test framework by following these steps:

First, we have to register a new test execution listener called: WithSecurityContextTestExecutionListener. This test execution listener sets up the SecurityContext before a test method is run and clears the used SecurityContext after each test method has been run.

After we have configured the required test execution listener, the relevant part of our integration test class looks as follows:

 1import com.github.springtestdbunit.DbUnitTestExecutionListener;
 2import com.github.springtestdbunit.annotation.DatabaseSetup;
 3import com.github.springtestdbunit.annotation.DbUnitConfiguration;
 4import org.junit.Before;
 5import org.junit.experimental.categories.Category;
 6import org.junit.runner.RunWith;
 7import org.springframework.beans.factory.annotation.Autowired;
 8import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
 9import org.springframework.test.context.ActiveProfiles;
10import org.springframework.test.context.ContextConfiguration;
11import org.springframework.test.context.TestExecutionListeners;
12import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
13import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
14import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
15import org.springframework.test.context.web.ServletTestExecutionListener;
16import org.springframework.test.context.web.WebAppConfiguration;
17import org.springframework.test.web.servlet.MockMvc;
18import org.springframework.test.web.servlet.setup.MockMvcBuilders;
19import org.springframework.web.context.WebApplicationContext;
20
21@RunWith(SpringJUnit4ClassRunner.class)
22@ContextConfiguration(classes = {IntegrationTestContext.class})
23@WebAppConfiguration
24@TestExecutionListeners({
25        DependencyInjectionTestExecutionListener.class,
26        TransactionalTestExecutionListener.class,
27        DbUnitTestExecutionListener.class,
28        ServletTestExecutionListener.class,
29        WithSecurityContextTestExecutionListener.class
30})
31@DatabaseSetup("/com/testwithspring/intermediate/tasks.xml")
32@DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader.class)
33@Category(IntegrationTest.class)
34@ActiveProfiles(Profiles.INTEGRATION_TEST)
35public class FindTaskWhenTaskIsFoundTest {
36
37    @Autowired
38    private WebApplicationContext webAppContext;
39
40    private MockMvc mockMvc;
41
42    @Before
43    public void configureSystemUnderTest() {
44        mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext)
45                .build();
46    }
47}

Second, we have to ensure that Spring MVC Test framework configures Spring Security when it creates a new MockMvc object. We can do this by adding the SecurityMockMvcConfigurer object into our configuration when we create a new MockMvc object.

This object creates a new springSecurityFilterChain bean and adds this bean as a filter. Also, this object ensures that the created security context is used when an HTTP request is send to the tested controller method.

After we have added the SecurityMockMvcConfigurer object into our configuration, the relevant part of our integration test class looks as follows:

 1import com.github.springtestdbunit.DbUnitTestExecutionListener;
 2import com.github.springtestdbunit.annotation.DatabaseSetup;
 3import com.github.springtestdbunit.annotation.DbUnitConfiguration;
 4import org.junit.Before;
 5import org.junit.experimental.categories.Category;
 6import org.junit.runner.RunWith;
 7import org.springframework.beans.factory.annotation.Autowired;
 8import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
 9import org.springframework.test.context.ActiveProfiles;
10import org.springframework.test.context.ContextConfiguration;
11import org.springframework.test.context.TestExecutionListeners;
12import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
13import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
14import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
15import org.springframework.test.context.web.ServletTestExecutionListener;
16import org.springframework.test.context.web.WebAppConfiguration;
17import org.springframework.test.web.servlet.MockMvc;
18import org.springframework.test.web.servlet.setup.MockMvcBuilders;
19import org.springframework.web.context.WebApplicationContext;
20
21import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
22
23@RunWith(SpringJUnit4ClassRunner.class)
24@ContextConfiguration(classes = {IntegrationTestContext.class})
25@WebAppConfiguration
26@TestExecutionListeners({
27        DependencyInjectionTestExecutionListener.class,
28        TransactionalTestExecutionListener.class,
29        DbUnitTestExecutionListener.class,
30        ServletTestExecutionListener.class,
31        WithSecurityContextTestExecutionListener.class
32})
33@DatabaseSetup("/com/testwithspring/intermediate/tasks.xml")
34@DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader.class)
35@Category(IntegrationTest.class)
36@ActiveProfiles(Profiles.INTEGRATION_TEST)
37public class FindTaskWhenTaskIsFoundTest {
38
39    @Autowired
40    private WebApplicationContext webAppContext;
41
42    private MockMvc mockMvc;
43
44    @Before
45    public void configureSystemUnderTest() {
46        mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext)
47                .apply(springSecurity())
48                .build();
49    }
50}

Next, we will find out how we can integrate Spring Security with Spring MVC Test framework when we are using Spring Boot.

Using Spring Boot

If we are using Spring Boot, we can integrate Spring Security with Spring MVC Test framework by registering a new test execution listener called: WithSecurityContextTestExecutionListener.

After we have registered the required test execution listener, the relevant part of our integration test class looks as follows:

 1import com.github.springtestdbunit.DbUnitTestExecutionListener;
 2import com.github.springtestdbunit.annotation.DatabaseSetup;
 3import com.github.springtestdbunit.annotation.DbUnitConfiguration;
 4import org.junit.experimental.categories.Category;
 5import org.junit.runner.RunWith;
 6import org.springframework.beans.factory.annotation.Autowired;
 7import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 8import org.springframework.boot.test.context.SpringBootTest;
 9import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
10import org.springframework.test.context.ActiveProfiles;
11import org.springframework.test.context.TestExecutionListeners;
12import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
13import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
14import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
15import org.springframework.test.context.web.ServletTestExecutionListener;
16import org.springframework.test.web.servlet.MockMvc;
17
18@RunWith(SpringJUnit4ClassRunner.class)
19@SpringBootTest(classes = {IntegrationTestContext.class})
20@AutoConfigureMockMvc
21@TestExecutionListeners({
22        DependencyInjectionTestExecutionListener.class,
23        TransactionalTestExecutionListener.class,
24        DbUnitTestExecutionListener.class,
25        ServletTestExecutionListener.class,
26        WithSecurityContextTestExecutionListener.class
27})
28@DatabaseSetup("/com/testwithspring/intermediate/tasks.xml")
29@DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader.class)
30@Category(IntegrationTest.class)
31@ActiveProfiles(Profiles.INTEGRATION_TEST)
32public class FindTaskWhenTaskIsFoundTest {
33
34    @Autowired
35    private MockMvc mockMvc;
36}

We don’t have to make any other changes to the configuration of our integration test class because the Spring Security’s MockMvc support is configured automatically if Spring Security is found from the classpath.

If you want to disable this feature, you have to to set the value of the @AutoConfigureMockMvc annotation’s secure attribute to false.

We can now integrate Spring Security with Spring MVC Test framework when we are using either Spring Framework or Spring Boot. Let’s summarize what we learned from this lesson.

Summary

This lesson has taught us four things:

  • We can get the required dependency by declaring the spring-security-test dependency in our build script.
  • The WithSecurityContextTestExecutionListener sets up the security context before a test method is run and clears the used security context after each test method has been run.
  • If we are using Spring Framework, we can configure the Spring Security’s MockMvc support by adding the SecurityMockMvcConfigurer object into our configuration when we create a new MockMvc object.
  • By default, Spring Boot configures the Spring Security’s MockMvc support automatically if Spring Security is found from the classpath.

Get the source code from Github