Trang chủ / Tự động hóa kiểm thử

Cách khắc phục kiểm thử chập chờn trong quy trình CI: Chẩn đoán từng bước

28/9/2026 ·

Cách khắc phục kiểm thử chập chờn trong quy trình CI: Chẩn đoán từng bước

Lỗi chập chờn là một trong những vấn đề tốn kém nhất trong kiểm thử phần mềm. Một bản build có thể qua ở lần chạy này nhưng lại thất bại ở lần chạy tiếp theo dù không hề thay đổi mã nguồn, khiến nhóm phải chạy lại job liên tục, trì hoãn phát hành và nghi ngờ mọi build báo đỏ. Hướng dẫn này trình bày cách xử lý kiểm thử chập chờn trong quy trình CI bằng cách chẩn đoán nguyên nhân trước khi chỉnh sửa bài kiểm thử, sau đó áp dụng các giải pháp kỹ thuật để kết quả có thể lặp lại một cách ổn định.

Xác định mẫu lỗi trước khi chạm vào bài kiểm thử

Bắt đầu bằng một bản ghi sự cố ngắn gọn. Ghi lại URL của job, mã commit SHA, nhánh, loại runner, dấu thời gian và thông báo lỗi hoặc assertion chính xác. Ghi chú xem lỗi xảy ra trên pull request, bản build nightly hay cả hai. Thông tin này giúp phân biệt vấn đề nằm ở bài kiểm thử hay ở hạ tầng.

Hãy tìm kiếm các mẫu hình thay vì các sự kiện đơn lẻ:

  • Bài kiểm thử chỉ lỗi trên một runner, hệ điều hành hoặc trình duyệt cụ thể?
  • Lỗi có xuất hiện sau khi tăng số lượng worker chạy song song không?
  • Lỗi có xảy ra khi dịch v�� mạng hoặc cơ sở dữ liệu đang chịu tải cao không?
  • Lỗi có xảy ra thường xuyên hơn khi gần ngưỡng timeout không?
  • Việc chạy lại cùng một commit có làm thay đổi kết quả không?

Một chỉ số ban đầu hữu ích là tỷ lệ lỗi trong 20 đến 50 lần chạy gần nhất. Một bài kiểm thử chỉ lỗi một lần trong 40 lần chạy vẫn tiêu tốn sự chú ý và có thể chặn phát hành. Hãy theo dõi tỷ lệ này theo từng môi trường để thấy liệu vấn đề có tập trung ở một làn chạy cụ thể hay không.

Tái hiện lỗi trong điều kiện được kiểm soát

Tái hiện biến một phàn nàn mơ hồ thành một nhiệm vụ kỹ thuật rõ ràng. Hãy chạy riêng bài kiểm thử đáng ngờ, sau đó chạy lại cùng toàn bộ suite. Nếu nó qua khi chạy riêng nhưng lỗi khi chạy chung, hãy nghi ngờ trạng thái dùng chung, tranh chấp tài nguyên hoặc phụ thuộc thứ tự. Nếu nó vẫn lỗi khi chạy riêng, hãy kiểm tra logic của bài kiểm thử và các phụ thuộc bên ngoài của nó.

Lặp lại lần chạy với cùng seed hoặc thứ tự khi framework hỗ trợ. Chỉ tăng mức chi tiết log vừa đủ để lộ ra các vấn đề về thời gian, retry và dọn dẹp. Lưu log dưới dạng artifact của CI để có thể so sánh các lần lỗi sau này. Trong lúc điều tra, tránh thêm các lệnh sleep ngẫu nhiên; chúng chỉ che giấu race condition thay vì chứng minh được nó.

Phân loại nguyên nhân gốc rễ

Hầu hết các lỗi chập chờn rơi vào một số ít nhóm nguyên nhân. Gọi tên đúng nhóm sẽ giúp việc sửa lỗi và phòng ngừa trở nên rõ ràng hơn.

Thời gian và vấn đề định thời

Các bài kiểm thử giả định một thao tác sẽ hoàn tất ngay lập tức rất dễ bị ảnh hưởng bởi CPU chậm, runner quá tải và quá trình garbage collection. Hãy chú ý các lệnh chờ cố định, các assertion được kiểm tra trước khi sự kiện kịp lan truyền và các timeout đặt quá sát với độ trễ thông thường. Thay các khoảng trễ tùy tiện bằng điều kiện tường minh: chờ cho request hoàn tất, hàng đợi được xử lý hết, tệp xuất hiện hoặc phần tử giao diện đạt trạng thái ổn định.

Trạng thái dùng chung và thứ tự thực thi

Các bài kiểm thử có thể phụ thuộc vào các dòng dữ liệu trong cơ sở dữ liệu, biến môi trường, tệp, cache hoặc singleton toàn cục do một bài kiểm thử trước đó tạo ra. Một suite có thể qua với thứ tự này nhưng lại lỗi với thứ tự khác. Hãy ưu tiên tạo fixture mới cho mỗi bài kiểm thử, dọn dẹp bằng transaction, dùng namespace riêng biệt và định danh duy nhất. Làm cho các bài kiểm thử đủ độc lập để chạy theo bất kỳ thứ tự nào và có thể chạy song song.

Hệ thống bên ngoài và hành vi mạng

Dịch vụ thực tế mang theo độ trễ, giới hạn tần suất, thay đổi DNS và sự cố một phần. Hãy quyết định bài kiểm thử nào cần dịch vụ thực và bài nào thì không. Giữ các kiểm thử hợp đồng gần ranh giới hệ thống, dùng test double có tính xác định cho hầu hết logic và dành kiểm thử end-to-end cho các hành trình quan trọng. Nếu bắt buộc phải gọi qua mạng, hãy đặt timeout tường minh, chỉ retry với các thao tác có tính idempotent và đảm bảo lỗi được quan sát rõ ràng.

Thiết kế bài kiểm thử và các giả định ẩn

Một số bài kiểm thử assert dựa trên thời gian thực, giá trị ngẫu nhiên, tập hợp không có thứ tự hoặc chi tiết triển khai vốn thay đổi giữa các bản build. Hãy làm cho assertion có tính xác định. So sánh dưới dạng tập hợp khi thứ tự không quan trọng, inject đồng hồ, cố định seed cho giá trị ngẫu nhiên và assert vào hành vi thay vì các lời gọi private. Đảm bảo việc dọn dẹp vẫn chạy ngay cả khi assertion thất bại.

Áp dụng bản sửa theo bước nhỏ an toàn nhất

Hãy sửa đúng nguyên nhân, không chỉ triệu chứng. Một lớp bọc retry có thể giảm nhiễu, nhưng cũng có thể che giấu một race condition thực sự và kéo dài thời gian phản hồi. Chỉ dùng retry như một hàng rào tạm thời trong lúc điều tra, sau đó loại bỏ khi vấn đề nền tảng đã được giải quyết.

Trình tự thực tế nên là:

  • Sửa khả năng đồng bộ hoặc việc dọn dẹp của bài kiểm thử.
  • Cô lập tài nguyên dùng chung và làm cho thứ tự thực thi không còn ảnh hưởng.
  • Giảm phụ thuộc bên ngoài hoặc làm cho chúng có tính xác định.
  • Điều chỉnh timeout dựa trên độ trễ đo được thực tế, không phải theo cảm tính.
  • Chỉ thêm retry có phạm vi hẹp cho thao tác thực sự có tính idempotent.

Khi có thể, hãy giữ mỗi thay đổi trong một commit riêng biệt. Điều này giúp dễ thấy thay đổi nào đã làm giảm tỷ lệ lỗi và dễ revert bản sửa gây ra sự bất ổn mới.

Khôi phục độ tin cậy cho pipeline

Sự tin cậy đến từ những tín hiệu nhất quán và minh bạch. Hãy cách ly bài kiểm thử chập chờn đã biết để nó không chặn công việc khác, nhưng vẫn giữ nó chạy trong một job định kỳ với người phụ trách và ngày gỡ cách ly rõ ràng. Báo cáo kiểm thử chập chờn như một chỉ số chính, bao gồm tỷ lệ lỗi, thời gian trung bình để phát hiện và thời gian để sửa.

Chạy các suite rủi ro cao với mức song song hợp lý, image runner ổn định và các phụ thuộc được ghim phiên bản. Lưu giữ các artifact như log, ảnh chụp màn hình, trace và giá trị seed cho các lần chạy lỗi. Xem xét thay đổi đối với bài kiểm thử với mức độ cẩn trọng như với mã nguồn production và yêu cầu bằng chứng cho thấy bản sửa đã làm giảm tỷ lệ lỗi.

Cuối cùng, hãy tổ chức một buổi tổng kết ngắn, không đổ lỗi khi một mẫu hình xuất hiện. Hỏi xem pipeline đã tiết lộ điều gì về vấn đề định thời, cô lập hay quản lý phụ thuộc, sau đó biến câu trả lời thành một mục trong checklist cho các bài kiểm thử sau này. Mục tiêu không phải là có một suite hoàn hảo ngay từ ngày đầu. Mục tiêu là một pipeline nơi build ��ỏ thực sự có nghĩa là cần chú ý, và build xanh có thể được tin tưởng.

Bài liên quan