Learning Outcome & Exercises: Testing
Tổng kết chương Testing: học xong mình phải làm được gì, và làm bài tập nào để chứng minh?
Đọc hiểu chưa đủ để đi phỏng vấn. Mỗi chương kết thúc bằng những việc làm được và chứng minh được: có code chạy, có test cho cả trường hợp lỗi, có log hoặc số đo. Bài tập nằm trong repo riêng java-backend-interview-labs, thư mục labs/testing.
1. Mục tiêu đầu ra
Học xong chương này, bạn tự làm được:
- Chọn đúng tầng test (unit / slice / integration / contract) cho từng rủi ro.
- Viết integration test với PostgreSQL thật qua Testcontainers.
- Viết test concurrency xác định được (không dựa vào sleep) và nhận diện flaky test.
2. Basic: Unit test với Mockito
Trạng thái: ⬜ Chưa triển khai: chưa có code/test, chưa tính là hoàn thành
Test OrderService: happy path, payment lỗi, verify không gửi email khi thất bại.
Bài liên quan: JUnit 5, Mockito
Hoàn thành khi:
- Coverage nhánh lỗi
- Không mock class đang test
3. Intermediate: Testcontainers
Trạng thái: ⬜ Chưa triển khai: chưa có code/test, chưa tính là hoàn thành
@DataJpaTest với PostgreSQL container, kiểm migration và query native.
Bài liên quan: Spring test slices, Testcontainers
Hoàn thành khi:
- Test chạy trên PostgreSQL thật (cần Docker)
- Ghi rõ nếu chưa chạy được
4. Challenge: Test concurrency không flaky
Trạng thái: ⬜ Chưa triển khai: chưa có code/test, chưa tính là hoàn thành
Test 2 transaction tranh một ghế bằng CountDownLatch/CyclicBarrier, chạy 50 lần liên tiếp đều xanh.
Bài liên quan: Test transaction & concurrency, Flaky test, Messaging, contract, E2E
Hoàn thành khi:
- Log 50 lần chạy
- Giải thích vì sao không dùng Thread.sleep
5. Tiêu chí hoàn thành chung
- Tự giải thích được bài toán và vì sao chọn giải pháp.
- Code chạy được bằng lệnh ghi trong README, không chứa secret.
- Có test tự động cho happy path và failure path.
- Có log hoặc số đo trong
evidence/chứng minh kết quả. - Có câu trả lời phỏng vấn ngắn bằng tiếng Việt và tiếng Anh.
- README của lab có link ngược về bài học tương ứng.
6. Lab và trạng thái
| Mức | Bài tập | Trạng thái | Test / bằng chứng |
|---|---|---|---|
| Basic | Unit test với Mockito | ⬜ Chưa triển khai: chưa có code/test, chưa tính là hoàn thành | — |
| Intermediate | Testcontainers | ⬜ Chưa triển khai: chưa có code/test, chưa tính là hoàn thành | — |
| Challenge | Test concurrency không flaky | ⬜ Chưa triển khai: chưa có code/test, chưa tính là hoàn thành | — |
Repo lab: java-backend-interview-labs/labs/testing. TODO: link GitHub là placeholder cho tới khi repo được push.
evidence/; chỉ đánh dấu xong khi có bằng chứng.Phỏng vấn hỏi về Testing, câu nào hay gặp nhất và trả lời sao?
Q1. Làm sao viết test concurrency không bị flaky?
🇻🇳 Tiếng Việt:
Không dựa vào sleep. Dùng latch hoặc barrier để ép interleaving cần kiểm tra, assert trên kết quả nghiệp vụ, có timeout cho mọi chờ đợi, và chạy lặp nhiều lần trong CI.
🇬🇧 English:
Do not rely on sleep. Use latches or barriers to force the interleaving under test, assert on business outcomes, put a timeout on every wait, and run the test repeatedly in CI.
Cách nhớ ngắn gọn
- Mỗi bài tập = code + test + log.
- Luôn có ít nhất một failure case.
- Chưa có bằng chứng thì chưa xong.
Tự kiểm tra
Bài tập Basic (Unit test với Mockito) được coi là xong khi nào?
Coverage nhánh lỗi; Không mock class đang test. Chưa có code chạy và bằng chứng thì chưa tính là xong.
Bài tập Intermediate (Testcontainers) được coi là xong khi nào?
Test chạy trên PostgreSQL thật (cần Docker); Ghi rõ nếu chưa chạy được. Chưa có code chạy và bằng chứng thì chưa tính là xong.
Bài tập Challenge (Test concurrency không flaky) được coi là xong khi nào?
Log 50 lần chạy; Giải thích vì sao không dùng Thread.sleep. Chưa có code chạy và bằng chứng thì chưa tính là xong.