Master Spring Boot Testing: Real‑World Cases and Advanced Techniques
This article provides a comprehensive guide to Spring Boot testing, covering core utilities, essential annotations, dependency libraries, web environment configurations, and practical code examples for unit, slice, and integration tests across JUnit, MockMvc, TestRestTemplate, JPA, Redis, and REST client scenarios.
1. Introduction
Spring Boot offers a rich set of testing utilities and annotations that simplify testing of applications. The testing support is provided by two modules: spring-boot-test (core features) and spring-boot-test-autoconfigure (automatic configuration for tests).
Spring Boot Test integrates with Spring Test and enhances mock capabilities, supporting unit tests, slice tests, and full‑stack functional tests.
2. Core Annotations and Dependencies
Key annotations include:
@Test – marks a unit test method.
@WebMvcTest – slice test for Spring MVC controllers.
@DataJpaTest – slice test for JPA repositories.
@SpringBootTest – full‑stack integration test.
The spring-boot-starter-test dependency brings the following libraries:
JUnit 5 – standard unit testing framework for Java.
Spring Test & Spring Boot Test – utilities for testing Spring Boot applications.
AssertJ – fluent assertion library.
Hamcrest – matcher library.
Mockito – mocking framework.
JSONassert – JSON assertion library.
JsonPath – JSON XPath support.
3. Web Environment Options
The @SpringBootTest annotation can customize the web environment via the webEnvironment attribute:
MOCK (default) – loads a mock web environment without starting an embedded server.
RANDOM_PORT – starts an embedded server on a random port.
DEFINED_PORT – starts an embedded server on a configured or default port (8080).
NONE – loads the application context without any web environment.
3.1 Reactive Web Type
<code>@SpringBootTest(properties = "spring.main.web-application-type=reactive")
public class SpringBootTest01 {}
</code>This configuration declares a reactive WebFlux application.
3.2 Passing Application Arguments
<code>@SpringBootTest(args = "--app.test=Pack")
public class MailServiceTest {
@Test
public void testAppArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("Pack");
}
}
</code>3.3 Mock Environment with MockMvc
<code>// Controller to be tested
@RestController
@RequestMapping("/demos")
public class DemoController {
@GetMapping("/index")
public Object index() { return "demo index"; }
}
// Unit test using MockMvc
@SpringBootTest
@AutoConfigureMockMvc
public class SpringBootTest02 {
@Test
public void testMockMvc(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/demos/index"))
.andExpect(status().isOk())
.andExpect(content().string("demo index1")); // intentional mismatch to show failure
}
}
</code>3.4 Running with Real Server (RANDOM_PORT)
<code>@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SpringBootTest03 {
@Test
public void testRestTemplate(@Autowired TestRestTemplate restTemplate) throws Exception {
String body = restTemplate.getForObject("/demos/index", String.class);
assertThat(body).isEqualTo("123");
}
}
</code>3.5 Mocking Beans with @MockBean
<code>// Existing component
@Service
public class RemoteService {
public String getValue() { return "RemoteData"; }
}
// Business component
@Service
public class BusinessService {
@Resource private RemoteService remoteService;
public String getReverseValue() {
return new StringBuilder(this.remoteService.getValue()).reverse().toString();
}
}
// Test class
@SpringBootTest
public class SpringBootTest04 {
@Resource private BusinessService businessService;
@MockBean private RemoteService remoteService;
@Test
public void exampleTest() {
given(this.remoteService.getValue()).willReturn("pack");
String reverse = this.businessService.getReverseValue();
assertThat(reverse).isEqualTo("kcap1"); // intentional mismatch to illustrate output
}
}
</code>4. Slice Tests
4.1 @WebMvcTest
<code>@RestController
@RequestMapping("/business")
public class BusinessController {
@Resource private RemoteService remoteService;
@GetMapping("/info")
public String info() { return this.remoteService.getValue(); }
}
@WebMvcTest(BusinessController.class)
public class SpringBootTest05 {
@Autowired private MockMvc mvc;
@MockBean private RemoteService remoteService;
@Test
public void testInfo() throws Exception {
given(this.remoteService.getValue()).willReturn("pack1");
mvc.perform(get("/business/info").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("pack"));
}
}
</code>4.2 @DataJpaTest
<code>@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class SpringBootTest06 {
@Autowired private TestEntityManager entityManager;
@Autowired private UserRepository repository;
@Test
public void testExample() {
User entity = new User();
entity.setAge(20);
entity.setName("pack");
this.entityManager.persist(entity);
User user = this.repository.findById(100001).orElse(entity);
assertThat(user.getName()).isEqualTo("pack1"); // intentional mismatch
}
}
</code>4.3 @DataRedisTest
<code>@DataRedisTest
public class SpringBootTest07 {
@Resource private PersonRepository personRepository;
// ... test logic ...
}
</code>4.4 @RestClientTest
<code>@Service
public class RemoteService {
@Resource private RestTemplate restTemplate;
public String remote() {
return this.restTemplate.getForObject("http://localhost:8088/demos/cf?ids=pack", String.class);
}
}
@RestClientTest(RemoteService.class)
@AutoConfigureWebClient(registerRestTemplate = true)
public class SpringBootTest07 {
@Resource private RemoteService service;
@Resource private MockRestServiceServer server;
@Test
public void getInfo() {
this.server.expect(requestTo("http://localhost:8088/demos/cf?ids=pack"))
.andRespond(withSuccess("pack", MediaType.TEXT_PLAIN));
String greeting = this.service.remote();
assertThat(greeting).isEqualTo("pack");
}
}
</code>4.5 TestRestTemplate
<code>public class SpringBootTest08 {
private final TestRestTemplate template = new TestRestTemplate();
@Test
public void testRequest() {
ResponseEntity<String> response = this.template.getForEntity(
"http://localhost:8088/demos/cf?ids=123pack", String.class);
assertThat(response.getStatusCode().is2xxSuccessful());
assertThat(response.getBody()).isEqualTo("pack");
}
}
</code> <code>@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SpringBootTest09 {
@Resource private TestRestTemplate template;
@Test
public void testRequest() {
ResponseEntity<String> response = this.template.getForEntity(
"http://localhost:8088/demos/cf?ids=123pack", String.class);
assertThat(response.getStatusCode().is2xxSuccessful());
assertThat(response.getBody()).isEqualTo("\"123pack\"");
}
@TestConfiguration(proxyBeanMethods = false)
static class RestTemplateBuilderConfiguration {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(1));
}
}
}
</code>The article concludes with a reminder that all provided examples are part of a continuously updated Spring Boot testing collection, freely available to readers.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.