Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn nhận nhiệm vụ kiểm thử một ô nhập tuổi trên form đăng ký. Ô này chấp nhận số từ 18 đến 60. Nếu bạn cố gắng "thử cho chắc", bạn có thể nhập 18, rồi 19, rồi 20, rồi 21... cho tới 60 — tổng cộng 43 giá trị hợp lệ. Chưa kể còn 0, 1, 2, ... 17 phía dưới và 61, 62, ... vô tận phía trên. Nếu mỗi lần nhập bạn còn phải điền cả form, bấm submit, chờ hệ thống phản hồi rồi kiểm tra kết quả, thì chỉ một ô nhập nhỏ xíu này đã ngốn của bạn cả buổi sáng.
Vấn đề là: chúng ta không bao giờ có đủ thời gian để kiểm thử tất cả các giá trị đầu vào có thể. Đây chính là điều bạn đã học ở bài "Bảy nguyên tắc kiểm thử theo ISTQB" — kiểm thử toàn diện (exhaustive testing) là bất khả thi. Nhưng bỏ bớt test case một cách tùy tiện thì lại nguy hiểm: biết đâu bạn bỏ đúng cái giá trị làm hệ thống sập.
Equivalence Partitioning (EP) — tạm dịch là "phân hoạch tương đương" hay "chia lớp tương đương" — là kỹ thuật giúp bạn giải quyết đúng bài toán này. Nó cho bạn một cách có hệ thống để cắt giảm số lượng test case xuống mức tối thiểu mà vẫn giữ được độ bao phủ hợp lý. Đây là một trong những kỹ thuật thiết kế test case nền tảng nhất, gần như xuất hiện trong mọi kỳ thi ISTQB và trong công việc hằng ngày của bất kỳ tester nào. Nắm vững EP, bạn sẽ viết test case gọn hơn, thông minh hơn, và biết cách bảo vệ lựa chọn của mình khi có người hỏi "sao anh chỉ test có mấy trường hợp thế?".
Khái niệm cốt lõi
Lớp tương đương là gì
Ý tưởng trung tâm của EP rất đơn giản và đẹp: nếu một nhóm giá trị đầu vào được hệ thống xử lý theo cùng một cách, thì chỉ cần test một giá trị đại diện cho cả nhóm là đủ. Nhóm giá trị đó gọi là một "lớp tương đương" (equivalence class hay equivalence partition).
Logic đằng sau là thế này: nếu giá trị 25 và giá trị 40 đều rơi vào cùng một nhánh code xử lý ("tuổi hợp lệ, cho phép đăng ký"), thì khả năng cao là nếu 25 chạy đúng thì 40 cũng chạy đúng, và ngược lại. Chúng "tương đương" với nhau về mặt hành vi. Vì vậy test 25 hay test 40 hay test 33 đều cho cùng một lượng thông tin — bạn chỉ cần chọn một.
Quay lại ví dụ ô tuổi 18–60, ta có thể chia toàn bộ trục số thành ba lớp:
- Lớp 1: tuổi nhỏ hơn 18 (không hợp lệ) — ví dụ đại diện: 10
- Lớp 2: tuổi từ 18 đến 60 (hợp lệ) — ví dụ đại diện: 35
- Lớp 3: tuổi lớn hơn 60 (không hợp lệ) — ví dụ đại diện: 75
Lớp hợp lệ và lớp không hợp lệ
Một điểm cực kỳ quan trọng mà người mới hay bỏ sót: EP không chỉ chia dữ liệu hợp lệ, mà còn phải chia cả dữ liệu KHÔNG hợp lệ.
- Valid equivalence class (lớp tương đương hợp lệ): các giá trị mà hệ thống nên chấp nhận và xử lý bình thường.
- Invalid equivalence class (lớp tương đương không hợp lệ): các giá trị mà hệ thống nên từ chối, báo lỗi, hoặc xử lý theo luồng ngoại lệ.
Một mẹo nhỏ về cách đếm test case
Có một quy tắc thực hành rất được ưa dùng: mỗi test case nên bao phủ càng nhiều lớp HỢP LỆ càng tốt (gộp chung để tiết kiệm), nhưng mỗi test case chỉ nên bao phủ ĐÚNG MỘT lớp KHÔNG hợp lệ tại một thời điểm.
Lý do: khi bạn nhập nhiều giá trị lỗi cùng lúc (ví dụ vừa sai tuổi vừa sai email), hệ thống thường chỉ báo lỗi đầu tiên nó gặp và dừng lại. Bạn sẽ không biết liệu lỗi thứ hai có được phát hiện hay không. Đây gọi là hiện tượng "che lỗi" (defect masking). Vì vậy, khi test giá trị không hợp lệ, hãy để mọi trường khác ở trạng thái hợp lệ, chỉ cho đúng một trường sai.
EP áp dụng cho những loại đầu vào nào
Đừng nghĩ EP chỉ dành cho các dải số. Nó áp dụng cho nhiều loại đầu vào:
- Dải số (numeric ranges): như ví dụ tuổi ở trên.
- Tập giá trị rời rạc (enumerations): ví dụ hạng thẻ thành viên gồm "Bạc / Vàng / Kim cương" — mỗi hạng là một lớp, cộng thêm một lớp cho giá trị không nằm trong tập.
- Chuỗi ký tự theo định dạng: ví dụ số điện thoại Việt Nam — lớp hợp lệ (đúng 10 số, đầu 0), lớp sai độ dài, lớp chứa ký tự chữ, lớp bỏ trống.
- Điều kiện logic: ví dụ "đã đăng nhập" và "chưa đăng nhập" là hai lớp.
- Đầu ra (output partitioning): đôi khi bạn chia lớp theo kết quả mong đợi, không chỉ theo đầu vào — ví dụ giao dịch dẫn tới "được duyệt", "chờ duyệt", "từ chối".
Tình huống thực tế
Ví dụ 1 — Sàn thương mại điện tử Tiki và ngưỡng freeship
Giả sử bạn là tester tại một sàn thương mại điện tử lớn ở Việt Nam kiểu như Tiki. Chính sách khuyến mãi mới: đơn hàng có tổng giá trị từ 149.000đ đến dưới 500.000đ được miễn phí vận chuyển tiêu chuẩn; đơn từ 500.000đ trở lên được miễn phí giao nhanh; đơn dưới 149.000đ tính phí ship bình thường.
Nếu không có EP, một tester non kinh nghiệm có thể ngồi thử vài chục mức giá ngẫu nhiên: 200k, 250k, 300k, 350k... và vẫn cảm thấy bất an vì không biết đã đủ chưa. Với EP, ta chia trục giá trị đơn hàng thành ba lớp rõ ràng:
- Lớp A: dưới 149.000đ → tính phí ship. Đại diện: 100.000đ
- Lớp B: từ 149.000đ đến dưới 500.000đ → freeship tiêu chuẩn. Đại diện: 300.000đ
- Lớp C: từ 500.000đ trở lên → freeship giao nhanh. Đại diện: 800.000đ
Bài học rút ra: EP biến một bài toán mơ hồ ("test bao nhiêu là đủ?") thành một quyết định có lập luận rõ ràng. Ba test case này chưa test biên (như 148.999đ hay 149.000đ chẵn) — phần biên đó sẽ do kỹ thuật Boundary Value Analysis ở bài sau đảm nhận. EP và BVA là cặp bài trùng: EP xác định các vùng, BVA soi kỹ ranh giới giữa các vùng.
Ví dụ 2 — Ứng dụng gọi xe và mã khuyến mãi
Hãy hình dung một startup gọi xe ở Đông Nam Á, tạm gọi là "GoRide", có ô nhập mã khuyến mãi khi đặt chuyến. Quy tắc: mã hợp lệ gồm đúng 8 ký tự, chỉ chữ in hoa và số, và phải còn hiệu lực trong hệ thống.
Một tester áp dụng EP sẽ không thử ngẫu nhiên hàng loạt mã, mà xác định các lớp:
- Lớp hợp lệ: mã đúng 8 ký tự, đúng định dạng, còn hạn — ví dụ "SALE2026"
- Lớp không hợp lệ về độ dài (quá ngắn): "SALE26"
- Lớp không hợp lệ về độ dài (quá dài): "SALE202699"
- Lớp không hợp lệ về ký tự: "sale@#26" (có ký tự đặc biệt và chữ thường)
- Lớp không hợp lệ về trạng thái: mã đúng định dạng nhưng đã hết hạn — "OLD12345"
- Lớp rỗng: không nhập gì
Bài học rút ra: Việc chia lớp buộc bạn phải nghĩ đến MỌI chiều mà đầu vào có thể sai — không chỉ định dạng mà cả trạng thái nghiệp vụ. Đây là lý do EP không phải là "chọn đại vài giá trị" mà là một quá trình phân tích có kỷ luật.
Ví dụ 3 — Cổng thanh toán và hạng khách hàng
Một fintech Việt Nam xử lý hạn mức chuyển tiền theo hạng tài khoản: tài khoản chưa xác thực (unverified) được chuyển tối đa 5 triệu/ngày; tài khoản đã xác thực CMND/CCCD (verified) được 100 triệu/ngày; tài khoản doanh nghiệp (business) được 1 tỷ/ngày.
Đây là trường hợp EP trên tập giá trị rời rạc (loại tài khoản) kết hợp với dải số (số tiền chuyển). Tester khôn ngoan sẽ lập ma trận lớp: với mỗi loại tài khoản, có lớp "trong hạn mức" và lớp "vượt hạn mức".
- Unverified + chuyển 3 triệu → cho phép
- Unverified + chuyển 6 triệu → chặn
- Verified + chuyển 50 triệu → cho phép
- Verified + chuyển 120 triệu → chặn
- Business + chuyển 800 triệu → cho phép
- Business + chuyển 1,2 tỷ → chặn
Bài học rút ra: Khi đầu vào có nhiều chiều (loại tài khoản × số tiền), EP giúp bạn nhìn ra bức tranh tổ hợp và không bỏ sót vùng nào. Với các bài toán tổ hợp lớn hơn nữa, bạn sẽ cần kỹ thuật Pairwise ở bài sau, nhưng EP luôn là bước phân tích đầu tiên.
Hướng dẫn từng bước
Đây là quy trình bạn có thể áp dụng cho bất kỳ đầu vào nào cần thiết kế test case bằng EP:
Bước 1 — Xác định các đầu vào cần phân tích. Đọc kỹ tài liệu đặc tả (requirement/spec) hoặc câu chuyện người dùng (user story). Liệt kê từng trường đầu vào, từng tham số, từng điều kiện. Ví dụ: ô tuổi, ô email, dropdown loại tài khoản.
Bước 2 — Với mỗi đầu vào, xác định các lớp tương đương. Hỏi: "Hệ thống xử lý những nhóm giá trị nào theo cùng một cách?". Nhớ chia cả lớp hợp lệ lẫn lớp không hợp lệ. Với dải số, thường có ba lớp cơ bản: dưới ngưỡng, trong khoảng, trên ngưỡng. Với tập rời rạc, mỗi giá trị hợp lệ có thể là một lớp, cộng thêm lớp "ngoài tập".
Bước 3 — Chọn một giá trị đại diện cho mỗi lớp. Với lớp hợp lệ, hãy chọn giá trị "điển hình" nằm giữa lớp, đừng chọn sát biên (biên để dành cho BVA). Với lớp không hợp lệ, chọn giá trị rõ ràng thuộc lớp đó.
Bước 4 — Thiết kế test case. Gộp nhiều lớp hợp lệ của các trường khác nhau vào một test case để tiết kiệm. Với mỗi lớp không hợp lệ, tạo một test case riêng, giữ mọi trường khác ở trạng thái hợp lệ để tránh che lỗi.
Bước 5 — Ghi rõ kết quả mong đợi. Mỗi test case phải nêu rõ hệ thống nên phản hồi thế nào: chấp nhận, báo lỗi gì, hiển thị thông báo nào. Test case không có kết quả mong đợi thì vô nghĩa.
Bước 6 — Rà soát độ bao phủ. Kiểm tra lại: mọi lớp đã có ít nhất một test case chưa? Có lớp nào bạn định nghĩa quá rộng khiến nó thực ra gồm nhiều hành vi khác nhau không? Nếu có, hãy tách nhỏ lớp đó ra.
Lỗi thường gặp & mẹo
Lỗi 1 — Chỉ chia lớp hợp lệ, quên lớp không hợp lệ. Đây là sai lầm phổ biến nhất của người mới. Bạn test rất kỹ luồng "mọi thứ đúng" nhưng lại để trống mảng dữ liệu rác. Nhớ rằng phần lớn crash nghiêm trọng đến từ input bất thường. Luôn tự hỏi: "còn cách nào để giá trị này SAI nữa không?".
Lỗi 2 — Định nghĩa lớp quá rộng. Giả sử bạn gộp "mọi số âm và mọi số lớn hơn 60" vào một lớp "không hợp lệ" duy nhất. Nhưng biết đâu hệ thống xử lý số âm bằng một nhánh code, còn số quá lớn bằng nhánh khác. Nếu vậy chúng KHÔNG thực sự tương đương và cần tách ra. Mẹo: khi nghi ngờ hai giá trị có thể đi qua hai nhánh code khác nhau, hãy tách thành hai lớp.
Lỗi 3 — Chọn giá trị đại diện sát biên. Nhiều người chọn ngay giá trị biên (như 18 hoặc 60) làm đại diện cho lớp hợp lệ. Điều này không sai nhưng làm lẫn lộn vai trò của EP và BVA. Với EP, hãy chọn giá trị "giữa lớp" (như 35) để test bản chất của lớp; để BVA lo phần biên.
Lỗi 4 — Test nhiều lỗi cùng lúc. Nhập một lượt cả tuổi sai và email sai rồi thấy báo lỗi, bạn tưởng đã test xong cả hai. Thực ra hệ thống có thể chỉ bắt lỗi đầu tiên. Hãy tách riêng từng lỗi.
Mẹo — Kết hợp EP với phân tích rủi ro. Không phải lớp nào cũng quan trọng như nhau. Với các lớp liên quan tới tiền bạc, bảo mật, hoặc tuân thủ pháp luật, bạn có thể chọn nhiều hơn một đại diện để chắc chắn. EP cho bạn khung tối thiểu, còn phán đoán nghiệp vụ giúp bạn biết chỗ nào cần thêm.
Mẹo — Dùng bảng để trình bày. Lập một bảng gồm cột "Lớp", "Loại (hợp lệ/không)", "Giá trị đại diện", "Kết quả mong đợi". Bảng này vừa là công cụ tư duy, vừa là tài liệu bàn giao rõ ràng cho đồng đội và reviewer.
Bài tập thực hành
Hãy áp dụng EP cho tình huống sau và tự viết ra danh sách lớp tương đương cùng giá trị đại diện.
Đề bài: Một ứng dụng đặt vé xem phim tại Việt Nam cho phép đặt vé theo quy tắc: mỗi giao dịch mua được từ 1 đến 8 vé. Khách hàng thường (regular) mua tối đa 8 vé; khách VIP mua tối đa 8 vé và được giảm 10%. Số vé phải là số nguyên dương. Ô nhập cũng cần từ chối giá trị 0, số âm, và giá trị không phải số.
Yêu cầu:
- Liệt kê tất cả các lớp tương đương cho trường "số lượng vé", phân rõ hợp lệ và không hợp lệ.
- Chọn một giá trị đại diện cho mỗi lớp.
- Thêm chiều "loại khách hàng" (regular / VIP / giá trị lạ) và lập ma trận các tổ hợp lớp cần test.
- Với mỗi test case, ghi rõ kết quả mong đợi.
- Chỉ ra test case nào là "gộp nhiều lớp hợp lệ" và test case nào "cô lập một lớp không hợp lệ".
Tóm tắt
Equivalence Partitioning là kỹ thuật thiết kế test case giúp bạn chia tập đầu vào khổng lồ thành các "lớp tương đương" — những nhóm giá trị mà hệ thống được kỳ vọng xử lý giống nhau — rồi chỉ chọn một giá trị đại diện cho mỗi lớp. Nhờ đó, bạn giảm mạnh số lượng test case mà vẫn giữ được độ bao phủ hợp lý và có lập luận rõ ràng.
Những điểm cốt lõi cần nhớ:
- Giá trị trong cùng một lớp được giả định hành xử như nhau, nên test một cái là đủ cho cả lớp.
- Luôn chia cả lớp hợp lệ lẫn lớp không hợp lệ — bug tệ nhất thường nằm ở dữ liệu rác.
- Mỗi test case nên gộp nhiều lớp hợp lệ nhưng chỉ cô lập một lớp không hợp lệ, để tránh hiện tượng che lỗi.
- Chọn giá trị đại diện nằm giữa lớp; phần biên hãy dành cho Boundary Value Analysis — EP và BVA là cặp kỹ thuật bổ trợ nhau.
- EP áp dụng cho dải số, tập rời rạc, chuỗi định dạng, điều kiện logic và cả đầu ra.