Part 02 · Testing & Code Quality · 2.1.03

Observable behavior, assertion và fixture

Một test tốt kể rõ điều kiện, hành vi và outcome. Fixture chỉ phục vụ câu chuyện đó, không được che mất behavior đang cần chứng minh.


1. Mental model: test public contract

Test nên quan sát contract thông qua return value, state transition, event hoặc interaction có ý nghĩa về mặt kiến trúc. Không gọi private method trực tiếp để “ép coverage”; nếu logic khó quan sát, hãy tách object hoặc boundary có trách nhiệm rõ hơn.

Arrange–Act–AssertGiven–When–Then là cấu trúc giúp người đọc nhận ra setup, hành động và outcome. Chúng không phải nghi thức cứng: điều quan trọng là mỗi test có một câu chuyện ngắn, deterministic và dễ chẩn đoán.

Rule of thumb: assert behavior và invariant trước; chỉ verify implementation interaction khi interaction đó chính là contract quan trọng, ví dụ payment không được charge lần hai.

2. Assertion design

Đừng chỉ assert “không throw”. Hãy assert outcome và invariant liên quan. Một behavior có thể cần nhiều assertion độc lập; assertAll giúp báo nhiều sai lệch cùng lúc nhưng không nên dùng để che một test đang kiểm tra quá nhiều behavior.

Với exception, kiểm tra exception type và dữ liệu nghiệp vụ; đồng thời xác nhận state không bị mutate sai:

var error = assertThrows(
    InsufficientBalanceException.class,
    () -> account.debit(new BigDecimal("20.00")));

assertAll(
    () -> assertEquals("INSUFFICIENT_BALANCE", error.code()),
    () -> assertEquals(new BigDecimal("10.00"), account.balance()));

3. Fixture nhỏ, rõ intent và có ownership

Fixture nên nhỏ, immutable khi có thể và thể hiện được dữ liệu quan trọng của test. Test Data Builder thường phù hợp hơn Object Mother khổng lồ: builder cung cấp default hợp lệ rồi cho phép override trường chính trong từng scenario.

Cách tạo fixtureƯu điểmRủi ro
Inline setupIntent nằm ngay cạnh assertion, dễ đọc với case nhỏ.Lặp lại nếu object có nhiều field.
Test Data BuilderDefault hợp lệ, override rõ field quan trọng.Builder quá thông minh sẽ che business rule.
Object MotherTạo nhanh object chuẩn dùng nhiều nơi.Dễ thành global fixture khổng lồ, thay đổi một default làm hỏng nhiều test.
Database fixtureKiểm tra behavior gần production.Cần reset strategy, unique key và transaction ownership.

4. Time, randomness, files và shared state

5. Failure modes

6. Câu hỏi phỏng vấn đào sâu

7. Checklist tự đánh giá

Nguồn tham khảo