Part 02 · Testing & Code Quality · 2.2

Câu hỏi kiểm thử và chất lượng

Trả lời theo cấu trúc: boundary cần chứng minh → rủi ro → loại test/công cụ → giới hạn và chi phí.


Cách luyện: Với mỗi câu, hãy nêu giả định, failure mode và evidence cần thu. Một câu trả lời senior không chỉ gọi tên annotation hay tool mà phải giải thích vì sao boundary đó đáng tin cậy.

1. Chiến lược

1. Unit test khác integration test ở boundary nào?
Unit test kiểm tra một unit hành vi với dependency ngoài boundary được thay thế. Integration test chạy sự hợp tác với công nghệ hoặc component thật như ORM, DB, broker hay Spring context. Tên annotation không tự quyết định loại test.
2. Test pyramid có phải tỷ lệ cố định?
Không. Nó là heuristic để giữ nhiều feedback nhanh và ít test rộng/chậm. Portfolio phụ thuộc kiến trúc, risk và chi phí failure; microservice nhiều integration boundary có thể cần nhiều component/contract test hơn.
3. Thiết kế test strategy cho REST + PostgreSQL + Kafka + payment gateway?
Unit test domain/state transition; MVC test HTTP contract; PostgreSQL container cho mapping/query/locking; Kafka container cho serialization, duplicate, retry/DLQ; mock hoặc stub gateway cho deterministic failure; contract test gateway; vài component/E2E critical journey. Mỗi layer có ownership và failure evidence.

2. JUnit và Mockito

4. JUnit Platform khác Jupiter?
Platform launch TestEngine và tích hợp build/IDE. Jupiter cung cấp API viết test cùng extension model và engine tương ứng. Có Jupiter API nhưng thiếu engine hoặc cấu hình discovery thì compile được nhưng test có thể không chạy.
5. Per-class test instance có rủi ro gì?
State instance được dùng lại giữa methods, tạo order dependency và race khi parallel. Chỉ dùng khi lifecycle hoặc resource yêu cầu và reset state rõ ràng.
6. Khi nào mock làm test kém tin cậy?
Khi mock chính behavior cần chứng minh, như SQL, transaction hoặc serialization; khi verify internal call sequence; hoặc mock quá nhiều khiến test chỉ xác nhận setup của chính nó. Mock boundary nondeterministic/expensive, còn integration risk dùng công nghệ thật.
7. Stub, mock, fake và spy khác nhau?
Stub cung cấp response; mock còn verify interaction; fake là implementation đơn giản hoạt động; spy bọc object thật và chỉ override một phần. Chọn theo mục tiêu test, không theo tiện lợi.

3. Spring và dữ liệu

8. So sánh @WebMvcTest, @DataJpaTest và @SpringBootTest
WebMvcTest tập trung MVC boundary; DataJpaTest tập trung JPA; SpringBootTest load full application context cho wiring và component behavior. Full context chậm và failure khó định vị nên không là mặc định.
9. Vì sao H2 test pass nhưng PostgreSQL production fail?
Dialect, type, collation, constraint, transaction isolation, locking và query planner khác. Nếu behavior phụ thuộc DB semantics, test bằng đúng engine/version family qua Testcontainers.
10. Vì sao @Transactional test có thể tạo false confidence?
Framework rollback sau test, cùng transaction có thể thấy dữ liệu chưa commit, và async/listener sau commit không chạy giống production. Muốn chứng minh commit visibility cần commit thật rồi đọc từ transaction khác.
11. Test optimistic locking thế nào?
Mở hai transaction độc lập, cùng đọc một version; cho transaction A commit update rồi B commit và kỳ vọng optimistic lock failure. Phải dùng DB thật và tránh test method bao toàn bộ trong một transaction duy nhất.

4. Reliability và quality

12. Test retry mà không làm test chậm?
Inject retry policy hoặc scheduler, hay dùng delay rất nhỏ ở test configuration; dependency fail N lần rồi thành công; verify số attempt, backoff policy và dừng đúng giới hạn. Không sleep theo thời gian production.
13. Test idempotency/duplicate message thế nào?
Gửi cùng idempotency key hoặc message ID nhiều lần, có thể concurrent, rồi assert chỉ một business side effect và response/result nhất quán. Kiểm tra persistence unique constraint hoặc inbox record chứ không chỉ verify mock.
14. Coverage 90% có chứng minh chất lượng?
Không. Coverage chỉ nói instruction hoặc branch được chạy. Test không assertion vẫn tăng coverage. Dùng coverage tìm khoảng trống, mutation test đánh giá sức phát hiện lỗi và review risk của code chưa được quan sát.
15. Mutation testing cung cấp tín hiệu gì?
Tool thay đổi logic rồi chạy test. Mutant bị kill nghĩa test phát hiện thay đổi; mutant sống nghĩa assertion thiếu hoặc code không quan sát được. Equivalent mutant và chi phí chạy là giới hạn.
16. Xử lý flaky test thế nào?
Thu seed, timing, order, environment và artifact; phân loại time/random/shared state/race/external dependency; tái hiện có kiểm soát; sửa root cause. Quarantine chỉ tạm thời, có owner và deadline; rerun không phải fix.
17. Parallel test có thể làm lộ lỗi gì?
Static/shared fixture, fixed port, cùng database row/schema, non-thread-safe mock/fake, global locale/timezone và container lifecycle. Chỉ bật sau khi isolation đúng.

5. Build và review

18. Maven test và verify khác nhau thế nào?
Test phase thường chạy unit tests. Verify chạy sau package/integration-test và phù hợp để xác nhận integration checks hoàn tất. Failsafe được thiết kế để cleanup/post-integration và verify vẫn chạy đúng khi integration test fail.
19. Rebase khác merge ở trade-off nào?
Merge giữ topology và commit identity; rebase replay để history tuyến tính nhưng rewrite commit. Không rebase shared public history tùy tiện. Chọn theo collaboration policy, không theo thẩm mỹ cá nhân.
20. Senior reviewer ưu tiên điều gì?
Correctness và invariant; security/data loss; compatibility/migration; concurrency/failure; observability và test evidence trước style. Reviewer hỏi why và trade-off, automation xử lý format.

6. Performance, security và CI operations

21. Contract test khác integration/E2E?
Contract test chứng minh producer/consumer cùng hiểu interface/schema mà không dựng toàn journey; integration chứng minh component với technology thật, E2E chứng minh flow rộng. Contract không thay runtime/network/failure test.
22. Property-based testing phù hợp khi nào?
Khi domain có invariant và input space lớn như money, parser hoặc state transition. Generator tạo cases, shrinking tìm counterexample nhỏ; vẫn cần example tests cho business narratives.
23. Performance test cần baseline gì?
Workload model, environment/resources, warm-up, arrival/concurrency, data size và percentile/error/saturation. So regression với uncertainty; average latency đơn lẻ không đủ.
24. Load, stress, spike và soak test?
Load kiểm target; stress tìm capacity/cliff; spike kiểm burst/recovery; soak tìm leak/degradation dài hạn. Mỗi loại có hypothesis và stop/safety conditions.
25. Security testing portfolio?
Threat model + unit authorization/validation, integration auth/token/data isolation, SAST/SCA/secret/container scan, DAST và targeted abuse tests. Scanner finding cần triage, không đồng nghĩa secure.
26. Dependency scan fail build khi nào?
Theo exploitability, reachability, severity, asset/exposure và fix/SLA policy; allowlist có owner, expiry và evidence. Không blind fail mọi CVE hoặc bỏ qua tất cả noise.
27. Test data có rủi ro gì?
Production dumps có PII/secrets và retention/access risk. Dùng synthetic hoặc masked data có referential/edge fidelity, least access, encrypted artifacts và cleanup policy.
28. Test selection trong monorepo?
Affected graph theo code/config/schema/contracts cộng dependency direction; chạy fast targeted PR checks và periodic/full safety net. Sai graph gây false green nên phải audit cache, key và coverage.
29. Quarantine flaky test quản thế nào?
Chỉ để unblock tạm: lưu evidence, owner, issue/severity/deadline, vẫn chạy ở lane quan sát và đo recurrence. Không xóa tín hiệu hoặc retry đến xanh.
30. CI runner và untrusted PR có risk gì?
PR code có thể đọc secrets/token, poison cache/artifact hoặc persistence trên self-hosted runner. Tách trust/events/runners, least permissions, ephemeral workspace và không cấp deployment credential.
Nguồn tham khảo