Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Thử nghiệm song song trong Ruby on Rails:Chiến lược giảm thiểu rủi ro và giảm thiểu

Bạn đã bao giờ nghe ai đó phàn nàn về việc bài kiểm tra của họ quá nhanh chưa? Tôi cũng vậy.

Kiểm tra nhanh có nghĩa là phản hồi nhanh. Cho dù bạn chạy chúng cục bộ hay trong một quy trình tích hợp liên tục, thử nghiệm của bạn càng kết thúc sớm thì bạn càng có thể phản ứng với các lỗi và cải thiện mã của mình sớm hơn. Bên cạnh việc tăng năng suất, ai cũng biết rằng các thử nghiệm chậm khiến các nhà phát triển trở nên gắt gỏng. Không ai thích nhà phát triển của họ gắt gỏng.

Với tất cả những gì đã nói, việc tạo một bộ thử nghiệm nhanh như chớp không phải lúc nào cũng dễ dàng như bạn mong đợi. May mắn thay, Rails 6 đã giới thiệu một tính năng thú vị được gọi là thử nghiệm song song . Thật dễ dàng để bắt đầu và có thể tăng tốc độ thử nghiệm của bạn lên rất nhiều. Tuy nhiên, có một số cạm bẫy cần lưu ý.

Thử nghiệm song song là gì?

Thử nghiệm song song có ý nghĩa gì?

Khi bạn chạy một bộ thử nghiệm, trình chạy thử nghiệm của bạn thường sẽ sinh ra một quy trình duy nhất để thực hiện lần lượt các thử nghiệm của bạn — hoặc hàng loạt . Một quy trình thử nghiệm duy nhất sử dụng một lõi CPU duy nhất. Như bạn có thể tưởng tượng, phương pháp này không tận dụng tối đa lợi thế của phần cứng hiện đại thường có hàng chục lõi CPU.

Bạn có thể có một chiếc MacBook ưa thích với 10 lõi CPU, nhưng thật đáng buồn, điều đó sẽ không giúp quá trình kiểm tra của bạn diễn ra nhanh hơn!

Chúng ta có thể thay đổi điều này bằng cách phân phối các bài kiểm tra riêng lẻ cho nhiều quy trình công nhân. Các bài kiểm tra sẽ không chạy nối tiếp nhau nữa mà chạy cạnh nhau — song song . Chạy bộ thử nghiệm của bạn trên hai trình chạy nhanh gấp đôi so với việc chạy cùng một bộ thử nghiệm trên một trình chạy duy nhất.

Máy của bạn càng có nhiều lõi thì càng có nhiều quy trình công nhân khả thi và do đó, bộ thử nghiệm của bạn sẽ hoàn thành càng nhanh. Giả sử bài kiểm tra của bạn thường mất tám phút để chạy. Việc chạy các thử nghiệm tương tự đó bằng bốn quy trình riêng biệt sẽ giảm thời gian chạy xuống còn khoảng hai phút!

Hãy tưởng tượng làm điều tương tự trên một cỗ máy 16 lõi đẹp đẽ, nơi chúng ta có thể tạo ra mười sáu công nhân. Thực sự rất hay!

Định cấu hình kiểm tra song song trong Rails

Vậy chúng ta đến đó bằng cách nào? Cho đến gần đây, bạn có thể sử dụng gem của bên thứ ba để song song hóa bộ thử nghiệm của mình, nhưng bắt đầu từ Rails 6, các thử nghiệm song song đã trở thành tiêu chuẩn. Dễ dàng như việc thêm parallelize vào bài kiểm tra của bạn:

 

Sử dụng cấu hình này, Rails sẽ tự động tạo ra các quy trình công nhân dựa trên số lượng bộ xử lý trong máy của bạn. Rails cũng sẽ tạo cơ sở dữ liệu được đặt tên (ví dụ:database-test-0 , database-test-1 , v.v.) để chạy thử nghiệm của bạn.

Đó là tất cả những gì cần thiết để bắt đầu! Tất nhiên, có một số tùy chọn cấu hình bổ sung nếu bạn cần.

Đôi khi, bạn có thể phải thực hiện thiết lập hoặc dọn dẹp cụ thể cho các thử nghiệm song song. Rails cung cấp hai hook để bạn sử dụng — parallelize_setupparallelize_teardown . Chúng được gọi trước và sau khi các tiến trình công nhân mới xuất hiện:

 

Bạn cũng có thể đặt số lượng công nhân theo cách thủ công:

 

Ngoài ra, hãy sử dụng PARALLEL_WORKERS biến môi trường để ghi đè cấu hình hiện có:

 

Ngoài ra còn có tùy chọn sử dụng các luồng thay vì các trình chạy để song song hóa bộ thử nghiệm của bạn.

 

with: :threads là tùy chọn mặc định khi sử dụng JRuby hoặc TruffleRuby. Về lý thuyết, việc sử dụng các luồng sẽ mang lại hiệu suất tốt hơn một chút. Rốt cuộc, các luồng yêu cầu ít chi phí hơn so với các tiến trình. Tuy nhiên, trong thực tế, tôi chưa bao giờ thấy việc sử dụng tất cả các luồng quá hữu ích và bạn chỉ cần sử dụng song song hóa dựa trên quy trình trong hầu hết các trường hợp là ổn.

Hãy coi chừng những cạm bẫy

Vì vậy, tất cả những gì bạn cần làm là thêm parallelize vào các thử nghiệm hiện có của bạn để trải nghiệm tốc độ tăng tốc đáng kinh ngạc? Thật dễ dàng!

Nếu bạn may mắn thì điều đó thực sự đúng. Có nhiều khả năng bạn sẽ gặp phải một số trục trặc không mong muốn khi lần đầu tiên thêm tính năng song song hóa vào bộ thử nghiệm hiện có của mình. Đây chắc chắn là trường hợp của tôi!

Chúng ta hãy giải quyết một điều. Nếu bạn sử dụng RSpec thay vì Minitest, bạn sẽ không gặp may. RSpec không hỗ trợ thử nghiệm song song tích hợp Rails 6. Có một cuộc thảo luận đang diễn ra về việc thay đổi điều đó, nhưng vẫn chưa có tiến triển đáng kể nào trong một thời gian. Nếu bạn muốn thử nghiệm song song với RSpec, cách tốt nhất của bạn vẫn là sử dụng các loại đá quý của bên thứ ba như Grosser/parallel_tests.

Một vấn đề không mong muốn khác mà bạn có thể gặp phải là việc chạy song song một số ít thử nghiệm sẽ chậm hơn sau đó chạy chúng một cách tuần tự. Việc thiết lập các thử nghiệm song song đòi hỏi chi phí đáng kể — chẳng hạn như tạo nhiều cơ sở dữ liệu — điều này có thể loại bỏ mọi lợi ích mà bạn có thể nhận được từ quá trình song song hóa.

Tốt hơn hết bạn nên tắt các thử nghiệm song song đối với một số lượng nhỏ các thử nghiệm. Bạn có thể làm như vậy bằng cách sử dụngPARALLEL_WORKERS biến môi trường:

 

Rails 7 đã giải quyết vấn đề này bằng cách chỉ cho phép thực thi song song khi bạn thực hiện nhiều thử nghiệm. Vì vậy, nếu bạn đã nâng cấp, bạn sẽ không gặp phải vấn đề này. Theo mặc định, ngưỡng song song được đặt thành 50, nhưng bạn có thể ghi đè:

 

Vấn đề cuối cùng tôi muốn nhấn mạnh là vấn đề mà bạn có nhiều khả năng gặp phải nhất và cũng là vấn đề khó giải quyết nhất và khó giải quyết nhất. Bạn có thể bắt đầu thấy các lỗi ngẫu nhiên khi bật thử nghiệm song song cho bộ thử nghiệm của mình. Để hiểu sự song song có thể gây ra điều này như thế nào, hãy xem một trường hợp thử nghiệm đơn giản:

 

Ngoài việc hơi vô dụng, bài kiểm tra này hoàn toàn ổn. Nó sẽ vượt qua 100% thời gian miễn là nó được chạy nối tiếp. Mỗi thử nghiệm đều được tách biệt và việc thực hiện các thử nghiệm này theo thứ tự ngẫu nhiên không khiến chúng thất bại. Điều đó thay đổi khi bạn thêm nhiều tiến trình hoặc luồng vào hỗn hợp.

Khi chạy thử nghiệm song song, thứ tự thực hiện của từng câu lệnh trong thử nghiệm của bạn có thể bị thay đổi do lập lịch CPU. Nhìn vào ví dụ, đôi khi bạn sẽ thấy các lệnh thực thi như lệnh này:

 

Vì Nhân viên 2 đã xóa tệp trước khi xác nhận của Nhân viên 1 được thực thi nên thử nghiệm đầu tiên đôi khi sẽ thất bại. Để gây thêm tổn thương, lệnh thi hành khác đôi khi sẽ khiến lần kiểm tra thứ hai thất bại và lần kiểm tra đầu tiên thành công.

Ví dụ đơn giản này minh họa một sự cố không chỉ xảy ra với các tệp mà còn với bất kỳ tài nguyên đơn lẻ nào mà các bài kiểm tra của bạn truy cập theo cách không an toàn theo luồng. Giả sử bạn ghi vào cơ sở dữ liệu Redis hoặc chỉ mục Elaticsearch. Trong trường hợp đó, bạn có thể gặp phải các biến chứng tương tự. Tệ hơn nữa, bạn có thể mất một thời gian để phát hiện ra tất cả các thử nghiệm gây ra lỗi ngẫu nhiên — và thậm chí còn mất nhiều thời gian hơn để khắc phục tất cả chúng.

Không có viên đạn bạc nào có thể giải quyết các thử nghiệm song song không ổn định. Nói chung, bạn sẽ cần đảm bảo rằng nhiều quy trình kiểm tra không chia sẻ tài nguyên. Đối với tệp, hãy sử dụng Tempfiles.Sử dụng parallelize_setup để tạo các tài nguyên được đặt tên (ví dụ:cơ sở dữ liệu Redis). Và vân vân.

Thêm thử nghiệm song song vào thử nghiệm Rails hiện có

Giả sử bạn gặp khó khăn với các lỗi kiểm thử ngẫu nhiên do quá trình song song hóa và không có thời gian để khắc phục chúng. Tuy nhiên, bạn vẫn muốn thu được lợi ích từ thử nghiệm song song. Bạn có thể chỉ muốn bật tính năng này cho một tập hợp con các bài kiểm tra của mình.

Chỉ những bài kiểm tra gọi parallelize rốt cuộc sẽ được song song hóa và bằng cách sử dụng các mối quan tâm hoặc lớp cha, bạn có thể thêm thử nghiệm song song vào bộ thử nghiệm của mình từng lớp thử nghiệm một. Bạn có thể tạo một mô-đun như thế này:

 

Mọi lớp kiểm thử có chứa mô-đun này giờ đây sẽ chạy song song:

 

Ngoài ra, bạn có thể tạo một lớp kiểm tra mới như ParallelTest :

 

Sau đó, kế thừa từ đó cho các thử nghiệm chạy song song — và loại bỏ những thử nghiệm có vấn đề.

Thử nghiệm song song dưới dạng Bandaid

Thử nghiệm song song mang lại tốc độ tăng ấn tượng mà không tốn nhiều công sức. Tuy nhiên, đừng để bị lừa:nó không thể thay thế các phương pháp khác để cải thiện tốc độ bộ thử nghiệm của bạn mà chỉ là một sự bổ sung.

Nếu bạn nhận thấy bộ thử nghiệm của mình chậm và có thể tiết kiệm công sức, hãy dành chút thời gian để phân tích nó và giải quyết các nguyên nhân gốc rễ dẫn đến sự chậm chạp. Bộ kiểm thử chậm được thêm vào kiểm thử song song sẽ nhanh hơn, nhưng không bao giờ nhanh bằng bộ kiểm thử vốn đã nhanh nhưng cũng chạy song song!

Kết thúc

Trong bài đăng này, chúng tôi đã xem xét thử nghiệm song song là gì, cách bạn có thể thiết lập và cách định cấu hình nó. Nếu bạn cần một cách để giúp quá trình kiểm thử của mình diễn ra nhanh hơn thì thử nghiệm song song sẽ cung cấp điều đó.

Bạn có thể gặp một số trở ngại khi thêm thử nghiệm song song vào bộ thử nghiệm của mình. Đừng ngạc nhiên khi các bài kiểm tra có thể chạy ổn định trong nhiều năm đột nhiên thất bại. Bạn có thể giải quyết chúng bằng cách chỉ song song hóa một tập hợp con của bộ thử nghiệm của mình.

Cho dù bạn chọn phương pháp nào, thử nghiệm song song vẫn là một công cụ tuyệt vời để tăng tốc độ thử nghiệm của bạn!

Chúc bạn viết mã vui vẻ!

Tái bút. Nếu bạn muốn đọc các bài đăng của Ruby Magic ngay khi chúng được đăng tải, hãy đăng ký nhận bản tin Ruby Magic của chúng tôi và không bao giờ bỏ lỡ một bài đăng nào!

Thử nghiệm song song trong Ruby on Rails:Chiến lược giảm thiểu rủi ro và giảm thiểu

Hans-Jörg Schnedlitz

Tác giả khách mời Hans của chúng tôi là kỹ sư Rails đến từ Vienna, Áo. Anh ấy dành phần lớn thời gian của mình để viết mã hoặc đọc về mã hóa, và đôi khi còn viết về nó trên blog của mình! Khi anh ấy không ngồi trước màn hình, bạn có thể sẽ tìm thấy anh ấy ở bên ngoài, đang leo núi.

Tất cả bài viết của Hans-Jörg Schnedlitz