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ừ không kiểm thử được và cách viết lại
Từ hay gặpCâu QA sẽ hỏiCách viết lại
NhanhBao 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ùngDễ 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àngLỗ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ợpTheo 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ốtTố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.

Bốn bước viết AC kiểm thử được Bước 1 và bước 3 là nơi AC thường bị thiếu nhất.
  1. Gom quy tắc: Con số, giới hạn, điều kiện áp dụng
  2. Viết đường chính: Một kịch bản thành công từ đầu tới cuối
  3. Thêm lỗi và biên: Sai, thiếu, hết hạn, dùng lại, chạm ngưỡng
  4. Đọ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.

Hai cách viết AC Chọn theo độ phức tạp của quy tắc, không theo thói quen.
  • 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 trước và sau khi viết lại, ví dụ minh họa
AC ban đầuVấn đềAC kiểm thử được
Khách nhập mã dễ dàngKhô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ã nhanhKhông có ngưỡng để đoSau 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ệnKhô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ã saiKhô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ạiTà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 đổiNế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.

Acceptance criteria và Definition of Done
Khía cạnhAcceptance criteriaDefinition of Done
Áp dụng choMột user story cụ thểMọi việc của team
Ai giữ chínhPO, soạn cùng dev và QACả team, đôi khi theo chuẩn của tổ chức
Có thay đổi khôngKhác nhau ở mỗi storyỔn định qua nhiều sprint
Ví dụĐơn dưới 300.000đ không áp được mã MAY10Code đã đượ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.

Checklist AC cho một user story
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]
Khung Given/When/Then
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