Part 02 · Testing & Code Quality · 2.1.05

Spring TestContext và test slices

Spring testing là bài toán chọn context boundary nhỏ nhất nhưng vẫn chứng minh được wiring và framework behavior cần thiết.


1. TestContext architecture

JUnit extension tạo và điều phối TestContextManager. Các listener tham gia dependency injection, transaction, SQL script, dirtiness và cleanup. Spring cache application context theo configuration key giữa các test class.

Profile, property override, mock bean hoặc @DirtiesContext có thể làm đổi key hoặc loại context khỏi cache, khiến suite chậm. Context caching là một phần của test architecture, không chỉ là tối ưu build.

Chẩn đoán suite chậm: xem test nào làm context cache miss, tránh dùng @DirtiesContext như cleanup mặc định và kiểm tra số lần full context khởi động trong CI report.

2. Chọn slice hay full context

Công cụBoundaryDùng khiTrade-off
@WebMvcTestMVC mapping, validation, serialization, filter/security liên quan.Controller contract và HTTP error response.Không chứng minh repository hoặc toàn bộ application wiring.
@DataJpaTestJPA mapping, repository query, constraint và persistence context.SQL/JPA behavior cần kiểm tra isolation.Không chứng minh web/security layer.
@JsonTestJSON serialization/deserialization.Schema, custom serializer và null/format behavior.Không chứng minh controller hoặc network.
@RestClientTestHTTP client với mock server.Request mapping, error mapping và retry client.Không chứng minh remote service thật.
@SpringBootTestFull application context và component behavior.Wiring hoặc interaction nhiều bean cần full context.Startup chậm, failure khó định vị, dễ tạo suite thiếu precision.

@SpringBootTest không nên là mặc định cho mọi test. Chọn slice khi risk nằm ở một boundary cụ thể; chỉ dùng full context khi wiring giữa nhiều layer là chính điều cần chứng minh.

3. MockMvc và real server

MockMvc đi qua DispatcherServlet pipeline nhưng không mở socket. Nó phù hợp để kiểm tra mapping, validation, exception handler và response serialization. Random-port test khởi động embedded server và HTTP stack thật hơn, phù hợp với network configuration, filter container hoặc client/server integration.

Quyết định dựa trên risk, không dựa trên sở thích: nếu socket, port, TLS hoặc server container là failure mode, MockMvc không đủ fidelity.

4. Database và Testcontainers

H2 hoặc database in-memory có SQL dialect và behavior khác PostgreSQL/MySQL. Với query, constraint, locking, isolation hoặc transaction semantics quan trọng, dùng Testcontainers chạy cùng database engine với production.

@Testcontainers
class OrderRepositoryTest {
    @Container
    static PostgreSQLContainer<?> postgres =
        new PostgreSQLContainer<>("postgres:17-alpine");
}

Container test vẫn cần schema setup, unique test data, cleanup và giới hạn thời gian hợp lý. Không nên biến container thành global mutable fixture mà test không có ownership.

5. Transaction-managed tests

Test-managed transaction thường rollback sau test, hữu ích cho isolation nhưng có thể che commit visibility, after-commit listener và async work. Nếu production behavior phụ thuộc commit thật, hãy commit chủ động rồi đọc từ transaction khác.

6. Failure modes

7. Checklist tự đánh giá

Nguồn tham khảo