If you're working on a Spring Security (and especially an OAuth) implementation, definitely have a look at the Learn Spring Security course:
>> LEARN SPRING SECURITYMocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Introduction
The ability to execute integration tests without the need for a standalone integration environment is a valuable feature for any software stack. The seamless integration of Spring Boot with Spring Security makes it simple to test components that interact with a security layer.
In this quick tutorial, weβll explore using @MockMvcTest and @SpringBootTest to execute security-enabled integration tests.
2. Dependencies
Letβs first bring in the dependencies weβll need for our example:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
The spring-boot-starter-web, spring-boot-starter-security, and spring-boot-starter-test starters provide us with access to Spring MVC, Spring Security, and the Spring Boot test utilities.
In addition, weβll bring in spring-security-test in order to get access to the @WithMockUser annotation that weβll be using.
3. Web Security Configuration
Our web security configuration will be straightforward. Only authenticated users will be able to access paths that match /private/** . Paths that match /public/** will be available for any user:
@Configuration
public class WebSecurityConfigurer {
@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.withUsername("spring")
.password(passwordEncoder.encode("secret"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(request -> request.requestMatchers(new AntPathRequestMatcher("/private/**"))
.hasRole("USER"))
.authorizeHttpRequests(request -> request.requestMatchers(new AntPathRequestMatcher("/public/**"))
.permitAll())
.httpBasic(Customizer.withDefaults())
.build();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
4. Method Security Configuration
In addition to the URL path-based security we defined in our WebSecurityConfigurer, we can configure method-based security by providing an additional configuration file:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfigurer
extends GlobalMethodSecurityConfiguration {
}
This configuration enables support for Spring Securityβs pre/post annotations. Other attributes are available as well if additional support is required. For more information on Spring Method Security, take a look at our article on the topic.
5. Testing Controllers With @WebMvcTest
When using the @WebMvcTest annotation approach with Spring Security, MockMvc is automatically configured with the necessary filter chain required to test our security configuration.
Because MockMvc is configured for us, weβre able to use @WithMockUser for our tests without any additional configuration:
@RunWith(SpringRunner.class)
@WebMvcTest(SecuredController.class)
public class SecuredControllerWebMvcIntegrationTest {
@Autowired
private MockMvc mvc;
// ... other methods
@WithMockUser(value = "spring")
@Test
public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
mvc.perform(get("/private/hello").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Note that using @WebMvcTest will tell Spring Boot to instantiate only the web layer and not the entire context. Because of this, controller tests that use @WebMvcTest will run faster than with other approaches.
6. Testing Controllers With @SpringBootTest
When using @SpringBootTest annotation to test controllers with Spring Security, itβs necessary to explicitly configure the filter chain when setting up MockMvc.
Using the static springSecurity method provided by SecurityMockMvcConfigurer is the preferred way to do this:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SecuredControllerSpringBootIntegrationTest {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
// ... other methods
@WithMockUser("spring")
@Test
public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
mvc.perform(get("/private/hello").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
7. Testing Secured Methods With @SpringBootTest
@SpringBootTest doesnβt require any additional configuration to test secured methods. We can simply call the methods directly and use @WithMockUser as needed:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SecuredMethodSpringBootIntegrationTest {
@Autowired
private SecuredService service;
@Test(expected = AuthenticationCredentialsNotFoundException.class)
public void givenUnauthenticated_whenCallService_thenThrowsException() {
service.sayHelloSecured();
}
@WithMockUser(username="spring")
@Test
public void givenAuthenticated_whenCallServiceWithSecured_thenOk() {
assertThat(service.sayHelloSecured()).isNotBlank();
}
}
8. Testing With @SpringBootTest and TestRestTemplate
TestRestTemplate is a convenient option when writing integration tests for secured REST endpoints.
We can autowire a template and set credentials before requesting secured endpoints:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SecuredControllerRestTemplateIntegrationTest {
@Autowired
private TestRestTemplate template;
// ... other methods
@Test
public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
ResponseEntity<String> result = template.withBasicAuth("spring", "secret")
.getForEntity("/private/hello", String.class);
assertEquals(HttpStatus.OK, result.getStatusCode());
}
}
TestRestTemplate is flexible and offers many useful security-related options. For more details on TestRestTemplate, check out our article on the topic.
9. Conclusion
In this article, we looked at several ways of executing security-enabled integration tests.
We looked at how to work with MVC controller and REST endpoints and also with secured methods.
