Computer >> Máy Tính >  >> Lập trình >> Ruby

Trường hợp của Bộ thử nghiệm Flaky

Gần đây, tôi đã làm việc trên một bộ thử nghiệm mà thực sự rất khó sử dụng do tính không đáng tin cậy của nó.

Ứng dụng mà bộ thử nghiệm đang nhắm mục tiêu là ứng dụng chỉ dành cho API Rails. Các bài kiểm tra được viết bằng JavaScript sử dụng một khuôn khổ có tên là Chakram, "một khuôn khổ thử nghiệm API được thiết kế để thực hiện các bài kiểm tra từ đầu đến cuối trên các điểm cuối JSON REST".

Vấn đề với bộ thử nghiệm là nó không xác định được. Một hàm hoặc chương trình có tính xác định nếu được cung cấp các đầu vào giống nhau, nó luôn cho các kết quả đầu ra giống nhau.

Bộ thử nghiệm cụ thể này sẽ vượt qua trong lần chạy đầu tiên, vượt qua trong lần chạy thứ hai, sau đó thất bại trong lần chạy thứ ba mà không có thay đổi nào được thực hiện đối với mã ứng dụng hoặc mã kiểm tra.

Tôi phát hiện ra rằng tôi có thể đưa bộ thử nghiệm trở lại trạng thái hoạt động bằng cách thực hiện rake db:reset . Các bài kiểm tra, hoạt động trên môi trường phát triển của ứng dụng Rails chứ không phải trên môi trường kiểm tra, phụ thuộc vào cơ sở dữ liệu của ứng dụng Rails đang ở trạng thái nhất định khi bộ kiểm tra bắt đầu chạy.

Đôi khi tôi có thể bắt đầu với một cơ sở dữ liệu mới được tạo hạt giống, chạy bộ thử nghiệm và sau đó chạy thành công bộ thử nghiệm lần thứ hai. Tôi thậm chí có thể chạy bộ thử nghiệm ba lần trở lên. Nhưng khá thường xuyên, bộ thử nghiệm bằng cách nào đó sẽ làm rối tung dữ liệu và tôi phải thực hiện một rake db:reset khác để đưa dữ liệu trở lại trạng thái mà bộ thử nghiệm có thể sử dụng thành công.

Tất nhiên đây không phải là cách mọi thứ nên diễn ra. Bộ thử nghiệm chỉ nên thất bại vì một lý do:mã mà bộ thử nghiệm ngừng hoạt động bình thường.

Những gì đáng lẽ phải được thực hiện thay thế

Vì vậy, nếu bộ thử nghiệm này được thiết lập theo cách có vấn đề, liệu có phải là cách thích hợp để thực hiện nó không?

Gốc của vấn đề là bộ thử nghiệm phụ thuộc vào việc thiết lập lại cơ sở dữ liệu được thực hiện theo cách thủ công bởi con người. Thay vào đó, mỗi thử nghiệm riêng lẻ trong bộ thử nghiệm nên tự động đặt cơ sở dữ liệu ở trạng thái sạch sẽ và sẵn sàng trước khi chạy. (Đây cũng là một thử nghiệm điển hình để xóa cơ sở dữ liệu sau khi chạy để nó không "rò rỉ" dữ liệu của nó sang các thử nghiệm khác. Điều này không hoàn toàn cần thiết nếu mọi thử nghiệm xóa cơ sở dữ liệu trước khi chạy, nhưng đó là một biện pháp bảo vệ tốt). )

Bộ thử nghiệm cũng nên nhắm mục tiêu đến môi trường thử nghiệm của ứng dụng Rails chứ không phải môi trường phát triển. Các hành động của nhà phát triển trong môi trường phát triển không được ảnh hưởng đến công việc của bộ thử nghiệm và ngược lại.

Các loại phụ thuộc có vấn đề khác

Trong câu chuyện của tôi, sự phụ thuộc có vấn đề là cơ sở dữ liệu không được làm sạch đúng cách.

Một loại phụ thuộc có vấn đề khác là một yêu cầu mạng. Hãy tưởng tượng bạn có một bộ thử nghiệm truy cập vào API Twilio. Bạn chạy bộ thử nghiệm vào thứ Ba và nó đã vượt qua. Sau đó, vào thứ Tư, bạn chạy cùng một bộ thử nghiệm và nó không thành công. Bạn không biết, Twilio đang bị ngừng hoạt động, và đó là lý do tại sao bộ thử nghiệm của bạn không thành công. Vài phút sau, sự cố ngừng hoạt động được giải quyết và bộ thử nghiệm của bạn hoạt động trở lại.

Điều này quay trở lại ý tưởng rằng kiểm tra chỉ nên thất bại vì một lý do và đó là nếu mã ứng dụng của bạn ngừng hoạt động.

Nếu bạn cần viết các bài kiểm tra cho mã tương tác với mạng, cách tốt hơn để làm điều đó (nếu bạn đang sử dụng Ruby / Rails) là sử dụng một công cụ như VCR cho phép bạn ghi lại các yêu cầu mạng và sau đó phát lại chúng sau đó mà không thực sự sử dụng internet.

Các trường hợp khi phụ thuộc bên ngoài được chấp nhận

Có thể lập luận rằng nếu một ứng dụng phụ thuộc vào API Twilio và API Twilio bị lỗi, thì ứng dụng đó thực sự đã bị hỏng và do đó, thử nghiệm thực sự sẽ thất bại. Làm cách nào để chúng tôi dung hòa ý tưởng này với ý tưởng rằng các bài kiểm tra không nên phụ thuộc vào các điều kiện bên ngoài?

Cách để dung hòa hai điều này là phân biệt giữa kiểm tra tích hợp , kiểm tra nhiều lớp hoặc hệ thống cùng nhau và kiểm tra đơn vị , kiểm tra một phần chức năng riêng lẻ.

Nếu một nhóm đưa ra quyết định có ý thức rằng một tập hợp các thử nghiệm nhất định của họ sẽ tấn công các dịch vụ bên ngoài trên toàn mạng để nhiều hệ thống có thể được kiểm tra cùng nhau, thì không có gì "sai" về điều đó. (Giải pháp thay thế sẽ là quyết định không thử kiểm tra các hệ thống đó cùng nhau.) Trong trường hợp này, nhóm sẽ chỉ cần lưu ý rằng bộ kiểm tra tích hợp phụ thuộc vào mạng của họ không được đảm bảo là xác định và có thể sẽ bong ra đôi khi . Một bộ thử nghiệm như thế này nên nằm tách biệt với tập hợp các thử nghiệm mà các nhà phát triển chạy trên máy của họ hàng ngày để kiểm tra các hồi quy.

Mặc dù có một ngoại lệ đối với quy tắc rằng các thử nghiệm không nên phụ thuộc vào các điều kiện bên ngoài, nhưng hầu hết thời gian quy tắc nên được tuân thủ, mang lại cho bộ thử nghiệm của bạn lợi ích là có tính xác định và đáng tin cậy.