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.
This lesson assumes that:
- You know how you can configure the application context of our integration tests
- You can integrate DbUnit with Spring Test framework
- You understand how you can override the default configuration of DbUnit
- You know how you can configure the Spring MVC Test framework
- You know how you can customize the configuration of your application context
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)
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}
Additional Reading:
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}
Additional Reading:
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.
@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-testdependency in our build script. - The
WithSecurityContextTestExecutionListenersets 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
MockMvcsupport by adding theSecurityMockMvcConfigurerobject into our configuration when we create a newMockMvcobject. - By default, Spring Boot configures the Spring Security’s
MockMvcsupport automatically if Spring Security is found from the classpath.