8.1 Testing Strategy & Test Slices
← Back to Chapter 8: Testing, Deployment & Production-Ready Spring Boot
A balanced testing pyramid combines fast unit tests, focused test slices, and end-to-end integration tests.
1. The Spring Boot Testing Pyramid
/ \
/ \ End-to-End (@SpringBootTest)
/ \ - Slowest, spins up full ApplicationContext
/-------\
/ \ Test Slices (@WebMvcTest, @DataJpaTest)
/ \ - Medium speed, loads only 1 architectural tier
/-------------\
/ \ Pure Unit Tests (JUnit 5 + Mockito)
/ \- Fastest (milliseconds), NO Spring context
/-------------------\
2. Spring Test Slices
Instead of bootstrapping hundreds of services and repositories, Test Slices instantiate only components relevant to the layer under test:
| Test Slice Annotation | What It Loads | Typical Collaborators Mocked |
|---|---|---|
@WebMvcTest(UserController.class) | @Controller, @RestControllerAdvice, Filter, MockMvc | Service dependencies (@MockBean) |
@DataJpaTest | @Entity, JpaRepository, embedded DB, SQL logging | Web layer, Services (completely excluded) |
@JsonTest | Jackson serializers and deserializers | Validates JSON formatting and dates |
Controller Slice Test with MockMvc:
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUserWhenFound() throws Exception {
UserDTO mockUser = new UserDTO(1L, "Sarwvidya", "sarvy@codewithsarvy.dev");
Mockito.when(userService.findById(1L)).thenReturn(mockUser);
mockMvc.perform(get("/api/v1/users/1")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.fullName").value("Sarwvidya"))
.andExpect(jsonPath("$.email").value("sarvy@codewithsarvy.dev"));
}
}
3. Full Integration Testing with @SpringBootTest
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class UserIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Test
void endToEndUserRegistration() throws Exception {
String payload = """
{
"email": "test@codewithsarvy.dev",
"fullName": "Test User",
"password": "Password123!"
}
""";
mockMvc.perform(post("/api/v1/users")
.contentType(MediaType.APPLICATION_JSON)
.content(payload))
.andExpect(status().isCreated());
assertTrue(userRepository.findByEmail("test@codewithsarvy.dev").isPresent());
}
}