Acceptance criteria là gì? Cách viết để QA kiểm thử được
Cách viết acceptance criteria rõ đến mức QA đọc xong là biết phải thử gì, kèm ví dụ mã giảm giá và mẫu dùng ngay.
Viết bởi Phan Lâm Duy Khôi
Acceptance criteria (AC) là các điều kiện một user story phải đạt để được coi là làm đúng. AC kiểm thử được khi mỗi dòng cho ra kết quả đạt hoặc không đạt rõ ràng, có số liệu cụ thể và có cả trường hợp lỗi, không dùng từ cảm tính như “nhanh” hay “dễ dùng”.
Ticket bị QA trả lại vì một chữ “nhanh”
Đây là tình huống minh họa. Bạn là PO của Mây Shop, một cửa hàng online bán trà và quà tặng. Bạn viết user story cho tính năng nhập mã giảm giá ở bước thanh toán, kèm ba dòng tiêu chí: “Khách nhập mã dễ dàng”, “Hệ thống áp mã nhanh”, “Báo lỗi rõ ràng khi mã sai”. Dev làm xong trong ba ngày.
Sang ngày thứ tư, bạn QA (người kiểm thử) nhắn hỏi: “Nhanh là bao nhiêu giây? Mã hết hạn thì báo gì? Đơn 299.000đ có dùng được mã cho đơn từ 300.000đ không? Khách xóa bớt hàng sau khi áp mã thì sao?”
Không câu nào khó. Nhưng không câu nào có câu trả lời trong ticket. Dev đã tự chọn một cách hiểu, QA đang đoán một cách khác, còn bạn là người duy nhất biết đáp án, hoặc nghĩ là mình biết. Mỗi câu hỏi như vậy là một vòng qua lại, và nếu không ai hỏi, lỗi sẽ đi thẳng tới khách.
Bài này nói về acceptance criteria: chúng là gì, vì sao viết ra rồi vẫn không kiểm thử được, và cách viết để QA đọc xong là biết phải thử gì. Phần viết user story, tức “ai cần gì và để làm gì”, bạn xem ở bài riêng bên dưới.
Acceptance criteria là gì?
Acceptance criteria, dịch là tiêu chí chấp nhận, thường gọi tắt là AC, là các điều kiện một user story phải đạt để được coi là làm đúng. Mỗi story có bộ AC riêng. Story nói ai cần gì và vì sao. AC nói cụ thể thế nào là đạt.
AC tốt có một đặc điểm dễ nhận ra: mỗi dòng cho ra kết quả đạt hoặc không đạt. Hai người khác nhau đọc cùng một dòng, thử trên cùng một bản build, phải đi tới cùng một kết luận. Agile Alliance mô tả acceptance test theo đúng tinh thần đó: kết quả là đạt hoặc không, và thường được viết dưới dạng ví dụ hoặc kịch bản sử dụng.
AC phục vụ ba người cùng lúc. Dev dùng AC để biết phải làm tới đâu thì dừng. QA dùng AC để biết phải thử những gì. PO dùng AC để nghiệm thu bằng một danh sách rõ ràng, thay vì bằng cảm giác “trông có vẻ ổn”.
Một lưu ý về thuật ngữ: Scrum Guide không định nghĩa acceptance criteria. Theo Scrum.org, AC không phải là một phần của Scrum mà là cách làm bổ sung nhiều team dùng để công việc minh bạch hơn. Vì vậy mỗi team có thể viết AC theo kiểu khác nhau, miễn là cả team hiểu giống nhau.
Vì sao AC hay không kiểm thử được?
Người mới viết AC thường không thiếu ý. Vấn đề là AC được viết như lời mô tả mong muốn, không phải như thứ ai đó sẽ cầm đi thử. Có năm kiểu lỗi hay gặp:
- Dùng từ cảm tính. “Nhanh”, “dễ dùng”, “thân thiện”, “rõ ràng”, “mượt” mô tả cảm giác bạn muốn người dùng có, không mô tả hành vi của hệ thống. Mỗi người đọc sẽ tự gán một ngưỡng khác.
- Chỉ viết đường đi suôn sẻ, còn gọi là happy path. Người viết hình dung khách nhập đúng mã, đơn đủ điều kiện, mạng ổn định. Nhiều lỗi lại nằm ở những đường đi khác.
- Viết giải pháp thay vì kết quả. “Hiện popup” hay “gọi API kiểm tra mã” nói cách làm, nhưng không nói thế nào là đạt. Nó còn trói tay dev khi có cách làm tốt hơn.
- Quy tắc nghiệp vụ nằm ngoài ticket. Mức giảm tối đa, ngày hết hạn, số lần dùng được nằm trong đầu PO, trong file của bộ phận marketing, hoặc trong một tin nhắn cũ.
- Gộp nhiều điều kiện vào một dòng. Một dòng có ba ý thì khi QA báo “không đạt”, không ai biết ý nào hỏng.
Một cách tự kiểm tra đơn giản: đọc từng dòng AC và hỏi “QA sẽ làm thao tác gì, rồi nhìn vào đâu để biết đạt?”. Nếu không trả lời được trong một câu, dòng đó chưa xong.
| Từ hay gặp | Câu QA sẽ hỏi | Cách viết lại |
|---|---|---|
| Nhanh | Bao nhiêu giây, đo từ lúc nào tới lúc nào? | Ghi một ngưỡng thời gian team đã chốt cùng dev, và thời điểm bắt đầu, kết thúc khi đo |
| Dễ dùng | Dễ với ai, làm được việc gì sau bao nhiêu bước? | Mô tả vị trí, số bước, hoặc việc người dùng hoàn thành được mà không cần hỗ trợ |
| Báo lỗi rõ ràng | Lỗi nào, hiện ở đâu, câu chữ là gì? | Liệt kê từng loại lỗi kèm nguyên văn thông báo và vị trí hiển thị |
| Hợp lệ, phù hợp | Theo quy tắc nào? | Ghi quy tắc cụ thể: định dạng, giới hạn, điều kiện áp dụng |
| Hoạt động tốt | Tốt nghĩa là gì? | Tách thành từng kết quả nhìn thấy được: số tiền, trạng thái, dữ liệu được lưu |
Cách viết acceptance criteria từng bước
Bạn không cần một buổi họp dài để viết AC. Với một story vừa phải, bốn bước dưới đây thường xong trong buổi sáng, phần lớn thời gian nằm ở bước 1 và bước 3.
- Gom quy tắc: Con số, giới hạn, điều kiện áp dụng
- Viết đường chính: Một kịch bản thành công từ đầu tới cuối
- Thêm lỗi và biên: Sai, thiếu, hết hạn, dùng lại, chạm ngưỡng
- Đọc cùng dev và QA: Sửa mọi chỗ còn phải đoán
Khi QA hỏi một câu mà AC chưa trả lời, thêm một dòng AC. Đừng chỉ trả lời trong chat.
Bước 1, gom quy tắc. Trước khi viết câu nào, liệt kê mọi con số và điều kiện của tính năng: áp dụng cho ai, từ bao nhiêu tiền, tối đa bao nhiêu, hết hạn lúc nào, dùng được mấy lần. Nếu một con số chưa có, ghi rõ là chưa có và ai sẽ quyết. Đó là câu hỏi mở, không phải chỗ để dev tự điền.
Bước 2, viết đường chính. Mô tả một lần dùng thành công: người dùng ở đâu, làm gì, hệ thống hiện gì. Viết bằng hành vi nhìn thấy được, như “tổng tiền giảm 30.000đ” hay “dòng Giảm giá hiện dưới Tạm tính”, thay vì “áp mã thành công”.
Bước 3, thêm lỗi và trường hợp biên. Đây là phần tạo ra khác biệt lớn nhất, nên có một mục riêng ngay bên dưới.
Bước 4, đọc cùng dev và QA. Đọc to từng dòng, mười lăm phút là đủ. Dev sẽ chỉ ra chỗ khó làm hoặc tốn công bất ngờ. QA sẽ hỏi những câu như trong tình huống mở đầu. Mỗi câu hỏi là một dòng AC còn thiếu. Nếu một câu hỏi làm thay đổi phạm vi, quyết luôn: làm trong story này, tách story khác, hay ghi vào phần ngoài phạm vi.
Checklist hay Given/When/Then: nên viết kiểu nào?
Có hai cách viết AC phổ biến. Cách nào cũng được, miễn là mỗi dòng kiểm thử được. Nhiều team dùng cả hai trong cùng một story.
- Checklist theo quy tắc: Mỗi dòng là một quy tắc ngắn, đánh dấu đạt hoặc không. Hợp với quy tắc độc lập, ít phụ thuộc vào trạng thái trước đó. “Mã không phân biệt chữ hoa và chữ thường.”
- Given/When/Then: Mỗi kịch bản có trạng thái ban đầu, một hành động và kết quả. Hợp với logic có điều kiện, ngưỡng, hoặc nhiều bước nối nhau. “Cho trước giỏ 299.000đ, khi nhập mã, thì hiện thông báo còn thiếu 1.000đ.”
Given/When/Then là một mẫu viết kịch bản: Given (cho trước) là bối cảnh ban đầu, When (khi) là hành động, Then (thì) là kết quả quan sát được. Agile Alliance mô tả đây là mẫu để viết acceptance test cho user story. Có công cụ như Cucumber đọc được mẫu này để chạy test tự động, nhưng bạn không cần công cụ nào vẫn dùng được nó như một khung suy nghĩ.
Bạn có thể giữ nguyên ba từ khóa tiếng Anh nếu team đã quen, còn phần nội dung viết bằng tiếng Việt. Điều quan trọng là mỗi kịch bản chỉ có một hành động ở phần When. Nếu bạn thấy mình viết “khi khách nhập mã rồi xóa hàng rồi nhập lại”, đó là ba kịch bản.
Một cách chọn nhanh: quy tắc nào bạn nói được trong một câu không có chữ “nếu” thì viết dạng checklist. Quy tắc nào cần “nếu… thì…” thì viết Given/When/Then.
Cần nghĩ tới những trường hợp lỗi và biên nào?
Trường hợp biên (edge case) là những tình huống nằm ở rìa của quy tắc: đúng bằng ngưỡng, ngay dưới ngưỡng, dữ liệu rỗng, thao tác lặp lại. Bạn không cần nghĩ ra mọi thứ. Đi qua danh sách dưới đây và giữ lại những tình huống có thể xảy ra và gây thiệt hại thật.
- Dữ liệu sai hoặc thiếu: nhập sai, để trống, có khoảng trắng thừa, sai định dạng.
- Ngưỡng: đúng bằng ngưỡng, thấp hơn một đơn vị, cao hơn mức trần.
- Thời gian và số lượng: hết hạn, chưa tới ngày bắt đầu, hết lượt dùng, hết hàng.
- Dùng lại và trùng lặp: dùng lần thứ hai, bấm nút hai lần, mở hai tab cùng lúc.
- Kết hợp với tính năng khác: mã khác đang áp, hàng đang giảm giá, phí giao hàng, điểm thưởng.
- Thay đổi giữa chừng: giỏ hàng thay đổi sau khi áp mã, khách quay lại bước trước.
- Quyền và trạng thái tài khoản: khách chưa đăng nhập, tài khoản mới, tài khoản bị khóa.
- Lỗi hệ thống: mất mạng, hệ thống thanh toán không phản hồi, thao tác bị gián đoạn.
Hai nguồn giúp bạn tìm biên tốt nhất là QA và bộ phận chăm sóc khách hàng. QA quen nghĩ theo hướng phá. Chăm sóc khách hàng biết khách thật hay vướng ở đâu. Hỏi họ một câu: “Với tính năng này, khách hay làm gì mà mình không ngờ tới?”
Với mỗi lỗi, AC nên nói ba điều: hệ thống chặn hay cho qua, người dùng thấy gì (ghi nguyên văn thông báo nếu đã chốt), và dữ liệu có bị thay đổi không.
Ví dụ: viết lại AC cho tính năng mã giảm giá
Quay lại Mây Shop. Đây là ví dụ minh họa, quy tắc và con số đều là giả định để luyện tập. Sau khi gom quy tắc ở bước 1, bạn có: mã MAY10 giảm 10% cho đơn có tạm tính từ 300.000đ (chưa gồm phí giao hàng), giảm tối đa 50.000đ, mỗi tài khoản dùng một lần, hết hạn lúc 23:59 ngày 30/11, mỗi đơn chỉ áp một mã.
| AC ban đầu | Vấn đề | AC kiểm thử được |
|---|---|---|
| Khách nhập mã dễ dàng | Không nói ô nhập ở đâu, nhập thế nào thì được chấp nhận | Ô nhập mã nằm ở bước thanh toán, ngay trên dòng Tổng cộng. Mã không phân biệt chữ hoa, chữ thường, khoảng trắng ở đầu và cuối được bỏ qua. |
| Hệ thống áp mã nhanh | Không có ngưỡng để đo | Sau khi bấm Áp dụng, tổng tiền cập nhật mà không tải lại trang, trong vòng 2 giây (số giả định, chốt cùng dev). |
| Giảm 10% cho đơn đủ điều kiện | Không nói đủ điều kiện là gì, không có mức trần | Đơn có tạm tính từ 300.000đ trở lên được giảm 10%, tối đa 50.000đ. Phí giao hàng không tính vào tạm tính. |
| Báo lỗi rõ ràng khi mã sai | Không tách loại lỗi, không có câu chữ | Ba thông báo riêng: mã không tồn tại, mã đã hết hạn, đơn chưa đủ giá trị kèm số tiền còn thiếu. |
| Không có | Bỏ sót trường hợp dùng lại | Tài khoản đã dùng MAY10 ở một đơn đã đặt thì không áp được nữa, hiện thông báo mã đã được sử dụng. |
| Không có | Bỏ sót trường hợp giỏ thay đổi | Nếu khách bớt hàng khiến tạm tính dưới 300.000đ, mã tự gỡ, tổng tiền cập nhật và hiện thông báo lý do. |
Ba dòng ban đầu thành sáu dòng, nhưng mỗi dòng giờ có một kết quả đạt hoặc không. Hai dòng cuối là chỗ dễ sinh lỗi: khách dùng lại mã, hoặc áp mã xong rồi bớt hàng để được giảm giá trên một đơn không đủ điều kiện.
Riêng phần ngưỡng và mức trần, viết dạng Given/When/Then sẽ rõ hơn, vì đây là logic có điều kiện:
- Kịch bản 1, đúng ngưỡng. Given giỏ hàng có tạm tính 300.000đ. When khách nhập MAY10 và bấm Áp dụng. Then dòng Giảm giá hiện 30.000đ và Tổng cộng giảm 30.000đ.
- Kịch bản 2, dưới ngưỡng. Given giỏ hàng có tạm tính 299.000đ. When khách nhập MAY10 và bấm Áp dụng. Then mã không được áp và hiện thông báo đơn còn thiếu 1.000đ để dùng mã.
- Kịch bản 3, chạm mức trần. Given giỏ hàng có tạm tính 600.000đ. When khách nhập MAY10 và bấm Áp dụng. Then dòng Giảm giá hiện 50.000đ, không phải 60.000đ.
QA đọc ba kịch bản này là biết phải tạo giỏ hàng nào, bấm gì và nhìn vào đâu. Dev đọc là biết phải xử lý mức trần. Không ai phải hỏi lại bạn.
AC khác Definition of Done thế nào?
Hai khái niệm này hay bị trộn lẫn. Nói ngắn: AC là điều kiện riêng của từng story, Definition of Done (DoD) là chuẩn chung cho mọi việc của team. Theo Scrum Guide, DoD là mô tả chính thức trạng thái của Increment khi đạt các chuẩn chất lượng cần có, và việc chưa đạt DoD thì chưa được phát hành.
| Khía cạnh | Acceptance criteria | Definition of Done |
|---|---|---|
| Áp dụng cho | Một user story cụ thể | Mọi việc của team |
| Ai giữ chính | PO, soạn cùng dev và QA | Cả team, đôi khi theo chuẩn của tổ chức |
| Có thay đổi không | Khác nhau ở mỗi story | Ổn định qua nhiều sprint |
| Ví dụ | Đơn dưới 300.000đ không áp được mã MAY10 | Code đã được review; mọi AC đã được QA kiểm trên staging |
Một story chỉ được coi là xong khi đạt cả hai: đúng AC của nó và đạt DoD của team. Nếu bạn thấy mình chép “đã viết unit test” vào AC của mọi story, dòng đó thuộc về DoD. Bài “Definition of Ready và Definition of Done” nói kỹ hơn về cách team xây DoD.
Mẫu AC để dùng ngay
Hai mẫu dưới đây dùng được cho hầu hết story. Mẫu đầu là checklist để bạn không quên phần nào. Mẫu sau là khung Given/When/Then cho các quy tắc có điều kiện. Copy rồi xóa những mục không áp dụng cho story của bạn.
Story: [tên hoặc link story] Quy tắc nghiệp vụ (con số, giới hạn, điều kiện): - [quy tắc 1] - [quy tắc 2] Đường chính: - [ ] Khi [người dùng làm gì] thì [hệ thống hiển thị, lưu hoặc gửi gì] Lỗi và trường hợp biên: - [ ] Dữ liệu sai hoặc để trống: [kết quả] - [ ] Đúng ngưỡng và ngay dưới ngưỡng: [kết quả] - [ ] Hết hạn, hết lượt, dùng lại: [kết quả] - [ ] Kết hợp với tính năng khác: [kết quả] - [ ] Thay đổi giữa chừng: [kết quả] - [ ] Lỗi mạng hoặc hệ thống: [kết quả] Thông báo hiển thị (ghi nguyên văn): - [thông báo 1] Ngoài phạm vi lần này: - [việc chưa làm] Câu hỏi còn mở (ai trả lời, trước ngày nào): - [câu hỏi]
Kịch bản: [tên ngắn, ví dụ: Đơn đúng bằng ngưỡng tối thiểu] Given (cho trước): [ai, đang ở đâu, dữ liệu ban đầu là gì] And: [điều kiện thêm, nếu có] When (khi): [một hành động duy nhất] Then (thì): [kết quả nhìn thấy hoặc kiểm tra được] And: [kết quả thêm: số tiền, thông báo, dữ liệu được lưu] Kịch bản: [trường hợp lỗi tương ứng] Given (cho trước): [trạng thái ban đầu] When (khi): [hành động] Then (thì): [hệ thống chặn hay cho qua, người dùng thấy gì]
Mục “Câu hỏi còn mở” rất đáng giữ. Nó cho cả team thấy chỗ nào chưa chốt, thay vì để dev tự đoán rồi tới lúc test mới lộ ra.
Năm lỗi người mới hay mắc khi viết AC
- Viết AC sau khi dev đã làm xong. Lúc này AC chỉ mô tả lại thứ đã có, không còn giúp ai làm đúng. Viết trước khi story vào sprint, hoặc ít nhất trước khi dev bắt đầu.
- Viết quá nhiều cho một story. Nếu AC dài tới hai, ba chục dòng, có lẽ story đang quá lớn. Cân nhắc tách story, ví dụ tách phần áp mã và phần báo cáo hiệu quả mã.
- Mô tả giao diện tới từng pixel trong AC. Màu nút, khoảng cách, cỡ chữ thuộc về thiết kế. AC nên trỏ tới bản thiết kế đã duyệt, rồi tập trung vào hành vi và quy tắc.
- Trả lời câu hỏi của QA trong chat mà không cập nhật ticket. Hai tuần sau, không ai nhớ đã chốt gì, và người mới vào team chỉ đọc ticket.
- Coi AC là việc riêng của PO. Bạn chịu trách nhiệm chính, nhưng viết một mình thì sẽ thiếu đúng những trường hợp mà dev và QA nhìn thấy rõ nhất.
Tóm tắt
- Acceptance criteria là điều kiện một user story phải đạt. Mỗi dòng nên cho ra kết quả đạt hoặc không đạt.
- Thay từ cảm tính như “nhanh”, “dễ dùng”, “rõ ràng” bằng hành vi, con số và câu chữ cụ thể.
- Viết theo bốn bước: gom quy tắc, viết đường chính, thêm lỗi và biên, đọc cùng dev và QA.
- Dùng checklist cho quy tắc đơn giản, Given/When/Then cho logic có điều kiện hoặc ngưỡng.
- AC là của từng story, Definition of Done là chuẩn chung của team. Story chỉ xong khi đạt cả hai.
Mình đang soạn thêm các tình huống PO khác theo cùng khung này, kèm mẫu dùng ngay. Nếu bạn muốn nhận khi có bài mới, đăng ký bản tin bên dưới.
Câu hỏi thường gặp
Acceptance criteria là gì?
Acceptance criteria (AC) là các điều kiện một user story phải đạt để được coi là làm đúng. Mỗi dòng AC nên cho ra kết quả đạt hoặc không đạt, để dev, QA và PO cùng đi tới một kết luận.
Ai viết acceptance criteria?
Product Owner thường chịu trách nhiệm chính về AC, nhưng nên soạn cùng dev và QA. Dev thấy được giới hạn kỹ thuật, QA thấy được các trường hợp lỗi mà người viết dễ bỏ sót.
Acceptance criteria khác Definition of Done thế nào?
AC là điều kiện riêng của từng user story, nói tính năng đó phải làm được gì. Definition of Done là chuẩn chất lượng chung áp dụng cho mọi việc của team, ví dụ đã review code, đã test, đã cập nhật tài liệu.
Nguồn kiểm tra
Bài liên quan
- User story là gì? Cách viết cho người mới, kèm mẫu và ví dụ: Mẫu “Là…, tôi muốn…, để…” là phần dễ. Bài này chỉ cách chọn đúng người dùng, đúng vấn đề và cắt story đủ nhỏ, kèm ví dụ trước và sau.
- Ưu tiên backlog khi việc nào cũng gấp: chọn cách nào?: Cách chọn giữa value vs effort, MoSCoW và RICE, tách hạn chót thật khỏi cảm giác gấp, và gửi stakeholder một ghi chú ưu tiên một trang.
- Cách nói không với sếp và stakeholder mà không mất lòng: Ba cách nói không thay cho một chữ “không”, cách xử lý khi người yêu cầu là sếp hoặc CEO, lúc nào nên escalate, kèm hội thoại mẫu và tin nhắn theo từng cấp.
- Sprint planning là gì? PO cần chuẩn bị gì trước buổi họp: Checklist chuẩn bị 1 đến 2 ngày trước sprint planning, cách dẫn phần “làm gì” và cách viết Sprint Goal, kèm mẫu dùng ngay.