Viết Test Cases
Nền tảng của mọi QA engineer: cách thiết kế, viết và duy trì test case chuyên nghiệp. Từ cấu trúc 9 thành phần đến các kỹ thuật thiết kế nâng cao.
📋Cấu Trúc Test Case Chuẩn Bắt buộc
Một test case chuẩn công nghiệp gồm 9 thành phần. Thiếu bất kỳ thành phần nào sẽ khiến test case khó tái sử dụng, khó debug và khó maintain.
-
Test Case ID
Mã định danh duy nhất. Format:
[Module]-[Type]-[Number]. Ví dụ:AUTH-POS-001(Authentication, Positive, case số 1). Đừng bao giờ dùng số thứ tự đơn giản như TC001 vì khó biết nó thuộc module nào. - Title / Summary Mô tả ngắn gọn, rõ ràng. Phải trả lời được "test gì" chỉ bằng cách đọc title. Xấu: "Test login". Tốt: "User logs in successfully with valid email and password".
- Preconditions Điều kiện phải thỏa mãn TRƯỚC khi chạy test. Ví dụ: "User account exists with email test@example.com", "Browser cleared cache", "Feature flag LOGIN_V2 is enabled". Thiếu preconditions → test flaky.
-
Test Data
Dữ liệu cụ thể dùng trong test. Không viết "nhập email hợp lệ" — phải là "nhập
qa.test+001@example.com". Specificity làm test reproducible. - Test Steps Từng bước thực hiện theo thứ tự. Mỗi step = một hành động duy nhất. Xấu: "Mở browser, đăng nhập, vào profile". Tốt: tách thành 3 steps riêng. Dùng động từ: Click, Enter, Select, Navigate, Verify.
- Expected Result Kết quả mong đợi cho MỖI step quan trọng và kết quả tổng thể. Phải measurable và observable. Xấu: "Login thành công". Tốt: "User được redirect sang /dashboard, hiển thị welcome message với username, session cookie được set với httpOnly flag".
- Priority P1 (Critical/Blocker), P2 (High), P3 (Medium), P4 (Low). Priority xác định thứ tự thực hiện và ảnh hưởng đến go/no-go decision. P1 failures = stop release.
- Test Type Positive / Negative / Edge Case / Performance / Security. Một feature cần đủ cả 4 loại mới gọi là coverage tốt.
-
Traceability
Link đến requirement/user story. Ví dụ:
REQ-AUTH-001,JIRA: AUTH-123. Đây là nền tảng của RTM (Requirements Traceability Matrix).
Ví dụ Test Case Hoàn Chỉnh — Feature: Login
| Field | Nội dung |
|---|---|
| TC ID | AUTH-POS-001 |
| Title | Đăng nhập thành công với email và password hợp lệ |
| Priority | P1 — Critical |
| Type | Positive |
| Req Link | AUTH-REQ-001, JIRA: AUTH-45 |
| Preconditions | 1. User account tồn tại với email qa.user@test.com / password Test@12342. Account không bị locked 3. Browser: Chrome latest, cache cleared |
| Test Data | Email: qa.user@test.comPassword: Test@1234 |
| Test Steps |
1. Navigate đến https://app.example.com/login2. Enter email vào field "Email address" 3. Enter password vào field "Password" 4. Click button "Sign In" |
| Expected Result |
- Sau step 4: HTTP 200, redirect sang /dashboard- Hiển thị: "Welcome back, QA User!" - Session cookie được set (httpOnly, Secure flags) - Navigation bar hiển thị avatar và username - Login history được ghi lại (verify trong DB nếu có access) |
| Pass/Fail | [ ] Pass [ ] Fail [ ] Blocked |
| Notes | Nếu redirect về /login lại → check network tab xem API response code |
🧪6 Kỹ Thuật Thiết Kế Test Case
Biết kỹ thuật giúp bạn tạo ra test cases có coverage tốt nhất với số lượng ít nhất — đây là điểm phân biệt QA giỏi và QA bình thường.
1. Equivalence Partitioning (EP)
Chia input domain thành các nhóm (partition) mà các giá trị trong cùng nhóm được xử lý giống nhau. Test 1 đại diện cho cả nhóm.
Ví dụ: Field "Tuổi" chấp nhận 18-65. Có 3 partition:
- Invalid low: < 18 (ví dụ: 15) → expect error
- Valid: 18-65 (ví dụ: 30) → expect accept
- Invalid high: > 65 (ví dụ: 70) → expect error
Chỉ cần 3 test cases thay vì test từng số từ 0-100.
2. Boundary Value Analysis (BVA)
Test tại các giá trị biên vì bugs thường xuất hiện ở đây (off-by-one errors). Với mỗi boundary, test: giá trị tại boundary, 1 dưới, 1 trên.
Ví dụ cùng field Tuổi 18-65:
| Test Value | Type | Expected |
|---|---|---|
| 17 | Below lower boundary | Error: "Tuổi phải từ 18" |
| 18 | At lower boundary | Accept |
| 19 | Above lower boundary | Accept |
| 64 | Below upper boundary | Accept |
| 65 | At upper boundary | Accept |
| 66 | Above upper boundary | Error: "Tuổi phải đến 65" |
3. Decision Table Testing
Dùng khi có nhiều conditions kết hợp với nhau. Liệt kê tất cả combinations của conditions và expected outcomes.
Ví dụ: Login với conditions: email valid (Y/N) × password correct (Y/N) × account active (Y/N):
| Email valid | Password đúng | Account active | Expected result |
|---|---|---|---|
| Y | Y | Y | Login thành công |
| Y | Y | N | Error: "Tài khoản bị khóa" |
| Y | N | Y | Error: "Sai mật khẩu" |
| Y | N | N | Error: "Sai mật khẩu" (account check sau) |
| N | - | - | Error: "Email không tồn tại" |
4. State Transition Testing
Dùng cho systems có states rõ ràng. Test các transition hợp lệ và không hợp lệ.
Ví dụ Order states: Pending → Processing → Shipped → Delivered và Pending/Processing → Cancelled
- Test happy path: Pending → Processing → Shipped → Delivered
- Test cancellation: Pending → Cancelled (valid)
- Test invalid: Delivered → Pending (không cho phép)
- Test invalid: Shipped → Cancelled (tuỳ business rule)
5. Error Guessing
Dựa trên kinh nghiệm và trực giác để đoán các nơi hay có bug. Không theo quy tắc cố định — đây là "nghệ thuật" của QA lâu năm.
- Nhập ký tự đặc biệt:
<script>alert(1)</script>vào text fields (XSS) - Submit form rỗng hoàn toàn
- Double-click button submit (duplicate submission)
- Copy-paste thay vì gõ tay vào password field
- Để form idle 30 phút rồi submit (session timeout)
- Nhập số âm vào quantity field
6. Use Case / User Journey Testing
Test theo luồng thực tế người dùng sẽ đi qua, không phải test từng feature riêng lẻ. Bắt các integration bugs.
Ví dụ E2E: Search sản phẩm → Xem chi tiết → Add to cart → Checkout → Payment → Nhận email xác nhận → Kiểm tra order history
🗄️Test Data Management
Test data kém là nguyên nhân hàng đầu khiến test cases flaky và không reproducible. Quản lý test data tốt là dấu hiệu của một QA team trưởng thành.
Static vs Dynamic Test Data
| Loại | Mô tả | Ưu điểm | Nhược điểm | Dùng khi nào |
|---|---|---|---|---|
| Static Data | Data được tạo trước và giữ cố định trong DB | Predictable, reproducible, nhanh setup | Có thể bị contaminate giữa test runs, cần reset | Reference data: country lists, product catalog, user roles |
| Dynamic Data | Data được tạo on-the-fly mỗi lần chạy test | Luôn fresh, không bị polluted, test isolation tốt | Chậm hơn, cần cleanup sau test | User accounts, orders, transactions, unique IDs |
Cách Tạo Test Data
- Manual creation: Tạo tay qua UI hoặc trực tiếp trong DB. Dùng cho small-scale testing hoặc khi data phức tạp.
- SQL scripts: Viết INSERT scripts để seed data. Luôn có cleanup script tương ứng. Lưu trong version control cùng code.
- Faker libraries: Dùng Faker.js, Python Faker, Bogus (.NET) để generate realistic fake data tự động.
- Snapshot từ production: Anonymize rồi import subset của production data. Đảm bảo compliance trước khi làm.
- Test data factory: Code pattern tạo objects với sensible defaults, chỉ override field cần test.
Data Masking cho PII
Các kỹ thuật masking:
- Substitution: Thay real name bằng fake name từ library (John Smith → Test User 001)
- Shuffling: Xáo trộn giá trị trong cùng column (email của user A đổi sang user B và ngược lại)
- Encryption: Mã hoá field nhưng giữ format (email → mã hoá nhưng vẫn có @domain.com)
- Nullification: Set về NULL hoặc default value cho fields không cần test
Lưu Trữ và Quản Lý
- Lưu test data scripts trong Git cùng với test cases
- Có README mô tả cách setup và reset data
- Separate data theo environment: dev, staging, UAT
- Document test accounts trong team wiki (không để trong code)
- Đặt lịch cleanup data cũ định kỳ (weekly/monthly)
👁️Test Case Review Process
Review là bước tạo ra quality trước khi chạy test. Một test case review tốt có thể catch 20-30% defects trong chính test cases.
Checklist Review
- Title có mô tả rõ "test gì" không? Đọc xong có hiểu ngay không?
- Preconditions đầy đủ và cụ thể chưa? Người khác có thể setup được không?
- Test steps có đủ chi tiết? Có bước nào mơ hồ không?
- Expected result có measurable và specific không, hay vẫn còn mơ hồ?
- Test data được chỉ rõ chưa? Có dùng real PII không?
- TC có link đến requirement chưa (traceability)?
- Priority có phù hợp với business impact không?
- Có cover negative cases không chỉ positive?
- Có overlap với TC khác không (duplicate effort)?
- Edge cases và boundary values đã cover chưa?
Peer Review vs QA Lead Review
| Aspect | Peer Review | QA Lead Review |
|---|---|---|
| Reviewer | QA engineer cùng level | Senior QA / QA Manager |
| Focus | Correctness, completeness, clarity | Coverage, strategy, risk alignment |
| Timing | Draft hoàn thành, trước execution | Sau peer review, trước sprint start |
| Outcome | Approve / Request changes | Final sign-off, prioritization |
| Frequency | Mọi TC mới hoặc major update | Per feature / per sprint |
Common Issues Tìm Thấy Trong Review
- Vague expected results: "hệ thống hiển thị thông báo" — thông báo gì? ở đâu?
- Missing negative tests: Chỉ có happy path, không test invalid inputs
- Unclear preconditions: "User đã login" — login với role gì? data gì?
- Steps too coarse: Một step làm nhiều việc, khó biết step nào fail
- No traceability: Không link req, không biết test cái này để làm gì
- Wrong priority: Bug cosmetic P1, critical business flow P3
🔧Test Case Maintenance
Test cases không phải write once — chúng cần được cập nhật liên tục theo evolution của product. Obsolete test cases là gánh nặng, không phải tài sản.
Khi Nào Cần Update Test Case
- Requirement thay đổi (feature change, new business rule)
- UI thay đổi (element bị rename, moved, redesigned)
- Bug fix làm thay đổi behavior của system
- Test case failed vì precondition không còn valid
- Test data không còn tồn tại hoặc outdated
- Test case tìm thấy gap mới trong quá trình execute
Version Control cho Test Cases
Trong các tool như TestRail, Zephyr, hoặc Xray, test cases có built-in versioning. Nếu dùng Excel/Google Sheet:
- Thêm cột "Version" và "Last Updated Date"
- Thêm cột "Change Log" ghi lý do update
- Lưu file trong Git hoặc SharePoint với version history
- Không xoá test case cũ — chuyển sang "Deprecated" status
Xử Lý Obsolete Test Cases
Đừng xoá ngay — nhiều công ty cần audit trail. Thay vào đó:
- Đánh dấu status "Obsolete" hoặc "Deprecated"
- Add comment lý do obsolete và ngày
- Link đến requirement change hoặc ticket làm nó obsolete
- Move vào folder "Archive" để tránh nhầm lẫn
- Sau 6 tháng, review lại — nếu vẫn không dùng thì xoá hẳn
⚠️8 Lỗi Phổ Biến Junior QA
Những lỗi này xuất hiện trong review của tôi hàng tuần. Đọc kỹ và tự kiểm tra lại test cases của bạn.
| # | Lỗi | Ví dụ xấu | Cách khắc phục |
|---|---|---|---|
| 1 | Expected result quá chung chung | "User đăng nhập thành công" | Specify: "Redirect sang /dashboard, hiển thị 'Welcome [name]', URL không còn /login" |
| 2 | Không test negative cases | Chỉ test đăng nhập đúng | Tạo test case cho: sai password, email không tồn tại, account locked, blank fields |
| 3 | Test steps quá gộp | "Step 1: Mở app, login, vào profile, update avatar" | Mỗi step = 1 action. Tách thành 4 steps riêng biệt |
| 4 | Preconditions mơ hồ | "Precondition: có user trong hệ thống" | "User 'qa.test@example.com' / 'Pass@123' tồn tại, role Admin, email verified" |
| 5 | Copy-paste test data trong steps | Mỗi step ghi lại toàn bộ data | Tách ra section Test Data riêng, steps chỉ reference "sử dụng data từ Test Data section" |
| 6 | Không có traceability | Test case không link req nào | Mỗi TC phải link ít nhất 1 requirement/user story. Nếu không có → hỏi lại BA/PM |
| 7 | Title không mô tả rõ | "TC-001: Test login" | Format: "[Subject] [action] [condition] → [expected]". Ví dụ: "Login fails when password has less than 8 characters" |
| 8 | Ignore boundary values | Field cho phép 1-100: chỉ test 50 | Luôn test: 0, 1, 2, 99, 100, 101, -1, max int, empty string |
Senior QA không chỉ viết test case "đúng" — họ viết test case "đúng chỗ". Đó là Risk-Based Prioritization: phân tích xem feature nào có nguy cơ fail cao nhất, ảnh hưởng lớn nhất đến user/business, và focus effort vào đó.
Senior hiểu tradeoff giữa coverage và time. Không có đủ thời gian để test 100% mọi thứ — Senior biết cắt đúng chỗ. Họ hỏi: "Nếu tôi chỉ có 4 giờ để test feature này trước release, tôi sẽ test gì?" và câu trả lời đó reflect hiểu biết về business risk, technical complexity và historical defects.
Junior viết nhiều TC nhưng miss critical paths. Senior viết ít hơn nhưng catch nhiều bug hơn vì họ test đúng chỗ.
✏️Bài Tập Thực Hành
Viết test cases đầy đủ cho feature "Đăng ký tài khoản"
Yêu cầu business:
- Username: 3-20 ký tự, chỉ cho phép a-z, 0-9, underscore. Phải unique trong hệ thống.
- Email: format hợp lệ, phải unique, hệ thống gửi verification email.
- Password: tối thiểu 8 ký tự, phải có ít nhất 1 chữ hoa và 1 số.
- Confirm Password: phải khớp với Password.
- Sau đăng ký thành công: hiển thị "Vui lòng kiểm tra email để xác thực tài khoản."
Nhiệm vụ:
- Xác định tất cả equivalence partitions cho mỗi field
- Xác định boundary values cho username và password length
- Tạo decision table cho tất cả error scenarios
- Viết ít nhất 15 test cases (positive + negative + edge cases) theo format chuẩn 9 thành phần
- Assign priority cho mỗi TC và giải thích tại sao