6 phút đọcRead in English
Automation testing là gì, và vì sao bộ test end-to-end dần xuống cấp
Automation testing là gì: unit, API và end-to-end test kiểm tra gì, kiểm thử tự động mang lại gì, và vì sao bộ test trên trình duyệt hay mất lòng tin.
Lần release nào cũng có cùng một câu hỏi: thay đổi này có làm hỏng thứ gì vốn đang chạy tốt không? Với một app nhỏ, một người có thể trả lời bằng cách bấm qua các luồng chính. Với một sản phẩm thật, có checkout, vài chục form và ba loại người dùng, không ai bấm hết được trước mỗi lần deploy. Sẽ có thứ bị bỏ qua, và thường đó lại chính là thứ bị hỏng.
Automation testing là việc viết bước kiểm tra đó thành code, để máy chạy lại theo đúng một cách, lần nào cũng như lần nào.
Ba loại test tự động
Phần lớn các team dùng kết hợp ba loại. Chúng khác nhau ở chỗ chạm vào bao nhiêu phần của hệ thống.
| Loại | Kiểm tra gì | Tốc độ thường gặp | Bỏ sót gì |
|---|---|---|---|
| Unit | Một hàm hoặc một class, tách riêng | Vài mili giây | Các phần ghép với nhau thế nào |
| API | Một service qua giao diện HTTP hoặc RPC | Vài chục mili giây tới vài giây | Thứ người dùng thực sự nhìn thấy |
| End-to-end | Một luồng thật trên trình duyệt thật, với app đang chạy | Vài giây tới vài phút | Rất ít, và đó là lý do nó chậm và dễ vỡ |
Một unit test có thể kiểm tra rằng hàm validate số điện thoại từ chối 09123 vì quá ngắn. Một API
test gửi số đó tới POST /orders và chờ mã 422. Một test end-to-end mở Storefront trên trình duyệt,
thêm hai sản phẩm vào giỏ, gõ số điện thoại ngắn đó vào form giao hàng, rồi kiểm tra trang có báo lỗi
và không cho khách thanh toán.
Trong ba loại, chỉ test end-to-end phát hiện được khi thông báo lỗi bị che sau nút Thanh toán trên màn hình nhỏ. Đó là giá trị của nó, và cũng là cái giá của nó.

Kiểm thử tự động mang lại gì
Kiểm tra regression lặp lại được. Một test chạy cùng các bước, cùng dữ liệu, lần nào cũng vậy. Nó không mỏi mắt ở ô nhập thứ bốn mươi, cũng không quên bước chỉ quan trọng với thanh toán khi nhận hàng. Khi một lỗi đã được fix, test tái hiện lỗi đó giữ cho nó không quay lại, hoặc ít nhất báo cho bạn biết khi nó quay lại.
Phản hồi nhanh trước khi release. Một bộ test chạy trên mỗi pull request phát hiện checkout bị hỏng khi người viết code còn nhớ rõ thay đổi của mình, chứ không phải hai ngày sau trong hàng đợi QA, càng không phải từ khách hàng.
Một định nghĩa chung về "xong". Test là một mô tả chính xác app phải làm gì. Khi được viết tốt, người mới vào team đọc test là hiểu tính năng hoạt động ra sao.
Unit test và API test mang lại những điều này khá ổn định. Bộ test end-to-end mới là nơi mọi thứ hay trục trặc.
Vì sao bộ test end-to-end dần xuống cấp
Team nào đã nuôi một bộ test trình duyệt được một năm đều quen kịch bản này. Lúc đầu có hai mươi test và rất nhiều tự tin. Một năm sau có ba trăm test, lần chạy hằng đêm đỏ gần như mỗi sáng, và thói quen bấm "chạy lại" cho tới khi xanh. Có vài nguyên nhân cụ thể dẫn tới đó.
Test flaky
Test flaky là test lúc pass lúc fail trên cùng một đoạn code. Nguyên nhân thường là thời gian: test bấm nút trước khi nút được bật, đọc tổng tiền trước khi request giảm giá trả về, hoặc phụ thuộc vào dữ liệu mà một test khác vừa sửa. Mỗi test flaky là một khoản thuế nhỏ. Có đủ nhiều, team học được cách lờ đi màu đỏ, và bộ test mất luôn lý do tồn tại.
Selector dễ vỡ
Test end-to-end tìm phần tử bằng một thứ gì đó: class CSS, vị trí trong DOM, một đoạn chữ. Khi designer đổi tên class hay chuyển ô mã giảm giá vào một panel thu gọn, test fail dù tính năng vẫn chạy đúng. Sửa thì không khó, nhưng phải có người sửa, nhiều khi là vài chục test cùng lúc.
Chi phí bảo trì
Mỗi lần tính năng thay đổi, các test bao phủ nó cũng phải đổi theo. Với unit test, chi phí đó nhỏ và cục bộ. Với test end-to-end thì lớn, vì một luồng đi qua nhiều trang. Khi deadline dí, team bắt đầu bỏ qua hoặc xoá những test khó sửa nhất, và đó thường là những test bao phủ các luồng phức tạp nhất.
Test không ai đọc nổi
Một file test 400 dòng với các hàm helper lồng ba tầng cho bạn biết code làm gì, chứ không cho biết test đó để làm gì. Khi nó fail, người trực phải đoán ngược lại ý đồ rồi mới quyết định được app hỏng hay test hỏng. Khi không ai đọc nổi một test, cũng không ai biết nó còn đáng giữ hay không.
Xanh chẳng nói lên gì, đỏ còn nói ít hơn
Một lần chạy end-to-end phụ thuộc vào rất nhiều thứ: trình duyệt, mạng, môi trường test, dữ liệu mẫu, đôi khi cả sandbox của bên thứ ba. Chỉ cần một thứ trục trặc là lần chạy fail, và trông nó y hệt một lỗi thật. Sau đủ nhiều lần báo động nhầm, màu đỏ không còn nghĩa là "app hỏng" mà thành "xem lại có phải do môi trường không". Màu xanh cũng chẳng hơn là bao nếu không ai biết bộ test bao phủ những gì.
Coverage không ai nói rõ được
Hãy hỏi một team xem bộ test checkout của họ bao phủ những trường hợp nào. Có thử số điện thoại 9 chữ số không? 11 chữ số? Địa chỉ dài đúng giới hạn? Câu trả lời thật thường là "để tôi mở code xem". Công cụ đo code coverage cho biết dòng nào đã chạy, chứ không cho biết input và giá trị biên nào đã được thử, nên cũng không trả lời được câu hỏi đó. Nếu không ai nói được bộ test bao phủ gì, cũng không ai nói được nó bỏ sót gì.
Không phải lý do để bỏ cuộc
Những vấn đề trên không phải lý lẽ chống lại test end-to-end. Chúng là lý do một bộ test tốt cần được làm có chủ đích: test design mà người khác review được, cách tìm phần tử ổn định, mỗi lần chạy tách biệt, và một ranh giới rõ giữa "app hỏng" và "môi trường test hỏng".
Ở bài tiếp theo, chúng tôi giới thiệu VibeQA, cách chúng tôi đưa những thói quen đó vào chính công cụ thay vì phó mặc cho kỷ luật của từng người.