Spring Testing¶
Spring Boot provides excellent testing support. Use @SpringBootTest for integration tests (loads full context), @WebMvcTest for controller-only tests (MockMvc), @DataJpaTest for repository tests (embedded DB). Use Mockito to mock dependencies. TestContainers enables testing with real databases. The testing pyramid: many unit tests, some integration tests, few end-to-end tests.
┌─────────┐
│ E2E │ Few — slow, expensive
│ Tests │
─┼─────────┼─
│Integration│ Some — test Spring context
│ Tests │
─┼───────────┼─
│ Unit Tests │ Many — fast, isolated
└─────────────┘
Unit Tests with Mockito¶
Unit tests test a single class in isolation — mock all dependencies with Mockito. Use @ExtendWith(MockitoExtension.class), @Mock for dependencies, @InjectMocks for class under test. Pattern: Given (setup mocks) → When (call method) → Then (assert + verify). Fast, no Spring context needed.
Deep Dive: Example & Annotations
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock private OrderRepository orderRepository;
@Mock private PaymentService paymentService;
@InjectMocks private OrderService orderService;
@Test
void shouldCreateOrder() {
// Given
when(orderRepository.save(any(Order.class))).thenReturn(savedOrder);
when(paymentService.charge(anyDouble())).thenReturn(true);
// When
Order result = orderService.createOrder(request);
// Then
assertThat(result.getId()).isEqualTo(1L);
verify(orderRepository).save(any(Order.class));
verify(paymentService).charge(20.0);
}
}
| Annotation | Purpose |
|---|---|
@Mock |
Create mock object |
@InjectMocks |
Inject mocks into class under test |
@Spy |
Partial mock (real methods unless stubbed) |
@Captor |
Capture arguments passed to mocks |
@WebMvcTest (Controller Tests)¶
Tests only the web layer — controllers, filters, advice. No services, repos, or DB. Uses MockMvc to perform HTTP requests and assert responses. Mock service-layer beans with @MockBean. Fast because it loads only web-related beans.
Deep Dive: Example
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired private MockMvc mockMvc;
@MockBean private UserService userService;
@Test
void shouldReturnUser() throws Exception {
when(userService.findById(1L)).thenReturn(new UserResponse(1L, "John", "john@test.com"));
mockMvc.perform(get("/api/users/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"))
.andExpect(jsonPath("$.email").value("john@test.com"));
}
@Test
void shouldValidateInput() throws Exception {
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""{"name": "", "email": "not-an-email"}"""))
.andExpect(status().isBadRequest());
}
}
@DataJpaTest (Repository Tests)¶
Tests JPA repositories with an embedded database (H2). Auto-configures EntityManager, repositories, and transaction rollback. Use TestEntityManager for test data setup. Fast, focused on data access layer only.
Deep Dive: Example
@DataJpaTest
class UserRepositoryTest {
@Autowired private UserRepository userRepository;
@Autowired private TestEntityManager entityManager;
@Test
void shouldFindByEmail() {
entityManager.persistAndFlush(new User("John", "john@test.com"));
Optional<User> found = userRepository.findByEmail("john@test.com");
assertThat(found).isPresent();
assertThat(found.get().getName()).isEqualTo("John");
}
}
@SpringBootTest (Integration Tests)¶
Loads the full Spring context. Use for end-to-end testing with TestRestTemplate or WebTestClient. WebEnvironment.RANDOM_PORT starts a real server. Slowest but most realistic. Use sparingly — rely on unit and slice tests for speed.
Deep Dive: Example & Web Environments
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderIntegrationTest {
@Autowired private TestRestTemplate restTemplate;
@Test
void shouldCreateAndRetrieveOrder() {
ResponseEntity<Order> response = restTemplate.postForEntity(
"/api/orders", request, Order.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
}
}
| WebEnvironment | Description |
|---|---|
MOCK (default) |
Mock servlet (use MockMvc) |
RANDOM_PORT |
Real server on random port |
DEFINED_PORT |
Real server on configured port |
NONE |
No web environment |
TestContainers¶
Test with real databases (PostgreSQL, MySQL, Redis, etc.) instead of H2. Uses Docker containers that start/stop automatically with tests. Configure via @Container and @DynamicPropertySource. Ensures tests match production database behavior.
Deep Dive: Example
@SpringBootTest
@Testcontainers
class UserRepositoryContainerTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired private UserRepository userRepository;
@Test
void shouldWorkWithRealPostgres() {
User user = userRepository.save(new User("John", "john@test.com"));
assertThat(user.getId()).isNotNull();
}
}
Testing Best Practices¶
- Use AssertJ for readable assertions. 2. Use
@MockBeansparingly (slows context). 3. Use@ActiveProfiles("test")for test config. 4. Use@Sqlfor test data. 5. Follow test pyramid: many unit tests, slice tests, few integration tests. Slice annotations:@WebMvcTest,@DataJpaTest,@WebFluxTest,@JsonTest,@RestClientTest.
Deep Dive: Slice Test Annotations
| Annotation | What It Loads |
|---|---|
@WebMvcTest |
Controllers, filters, advice only |
@DataJpaTest |
JPA repos, EntityManager, DataSource |
@WebFluxTest |
WebFlux controllers |
@JsonTest |
Jackson ObjectMapper |
@RestClientTest |
RestTemplate/WebClient |
Common Interview Questions¶
Common Interview Questions
- What is the difference between
@SpringBootTestand@WebMvcTest? - What is MockMvc? How do you use it?
- What is the difference between
@Mockand@MockBean? - When would you use
@DataJpaTest? - What is TestContainers? When would you use it?
- What is the testing pyramid?
- How do you test REST APIs in Spring Boot?
- What are slice test annotations?