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

Làm chủ VCR trong Ruby: Tăng hiệu suất & Độ tin cậy Test

Nếu ứng dụng Ruby của bạn dùng bất kỳ external API nào, bạn có thể đã gặp vấn đề test chậm & giới hạn rate limit API.

Giải pháp là gì?

Bạn có thể thủ công stub phương thức HTTP từ client library, và trả về phản hồi xác định trước.

Nhưng đó là nhiều việc & code xấu xí!

Giải pháp tốt hơn là dùng kết hợp gem mạnh mẽ như Webmock + VCR.

WebMock chặn (intercept) HTTP request từ các HTTP library phổ biến, như:

  • net/http
  • Faraday
  • RestClient
  • …nhiều hơn nữa!

Điều này đơn lẻ đã hữu ích, nhưng bạn vẫn phải cung cấp dữ liệu phản hồi.

Đây là nơi VCR xuất hiện…

VCR làm việc kết hợp với WebMock để ghi lại HTTP response do code của bạn tạo ra.

Các bản ghi này gọi là "cassettes" (băng cassette).

Khi bạn chạy test:

VCR sẽ load file cassette & trả về response đã ghi. Bạn sẽ nhận phản hồi nhanh hơn vì không phải hỏi API thật.

Hãy xem vài ví dụ code!

Ví dụ code VCR

Cho ví dụ này, chúng ta sẽ dùng RSpec vì nó tích hợp tốt hơn với VCR như bạn sẽ thấy ở phần sau.

Code chúng ta muốn test:

require "faraday"
require "json"
class Github
  def self.user(name)
    url = "https://api.github.com/users/#{name}"
    data = Faraday.get(url).body
    JSON.parse(data, symbolize_names: true)
  end
end

Nó tạo request đến Github API để lấy thông tin user cụ thể. Khá đơn giản nhưng nó sẽ giúp chúng ta học cách VCR hoạt động.

Test cho code này có thể trông như sau:

require "rspec/autorun"
require_relative "github_api_example"
describe Github do
  let(:user_response) { Github.user("ruby") }
  it "can fetch & parse user data" do
    expect(user_response).to be_kind_of(Hash)
    expect(user_response).to have_key(:id)
    expect(user_response).to have_key(:type)
  end
end

Điều này sẽ hit API thật & pass, nhưng mất khoảng nửa giây để chạy.

Nửa giây cho MỘT test!

Có vẻ không nhiều, nhưng tưởng tượng bạn có trăm test, đó là 50 giây để chạy tất cả.

Đã đến lúc sửa…

Hãy giới thiệu VCR bằng cách thêm code này:

require "vcr"
VCR.configure do |c|
  c.cassette_library_dir = "spec/vcr"
  c.hook_into :webmock
end

Bạn có thể thêm code này trong file test_helper, để nó có sẵn cho tất cả test

Với block configure này, bạn đang nói cho VCR biết nơi lưu file cassette, và bật tích hợp WebMock.

Nếu bạn dùng Faraday, hoặc Excon, VCR có thể hook vào đó trực tiếp.

Chỉ cần thay :webmock bằng :faraday, hoặc :excon.

Tiếp theo:

Bạn phải nói cho VCR tên cassette & code nào nên chạy dưới cassette đó.

Cách làm:

let(:user_response) do
  VCR.use_cassette("github/user") { Github.user("ruby") }
end

Khi bạn chạy test, VCR sẽ tạo file dưới cassette_library_dir, trong trường hợp này tên file sẽ là spec/vcr/github/user.yaml, nếu bạn đang theo dõi, bạn có thể muốn xem nó.

Nếu tôi chạy test bây giờ, nó sẽ nhanh hơn rất nhiều.

Thực tế…

Chỉ mất 0.01 giây để xong!

"An HTTP request has been made that VCR does not know how to handle"

Nếu bạn gặp thông báo lỗi này, nghĩa là một trong hai chuyện:

1. Bạn đang cố tạo HTTP call với VCR bật, nhưng bên ngoài block VCR.use_cassette.

Giải pháp: Mặc định VCR + WebMock chặn tất cả HTTP request. Bạn có thể thay đổi bằng tùy chọn config, thêm block VCR thiếu, hoặc dùng RSpec metadata (phần sau).

2. Bạn đang cố tạo request khác & dùng cassette không khớp URL này. Ví dụ, nếu request trong test là /users/ruby, cassette được tạo cụ thể cho URL này, nếu bạn đổi test thành /users/apple thì bạn sẽ thấy lỗi này vì cassette cho URL khác.

Giải pháp: Dùng cassette khác cho URL khác, bật chế độ ghi new_episodes (vcr: { record: :new_episodes }) hoặc xóa cassette cũ sau khi cập nhật URL request.

Cách dùng RSpec Metadata

Phương thức VCR.use_cassette là cách tốt để dùng gem này.

Nhưng…

Bạn cũng có thể để VCR tự tạo cassette cho bạn.

Làm thế nào?

Thêm này bên trong block VCR.configure:

c.configure_rspec_metadata!

Bây giờ bạn có thể bật VCR cho test cụ thể (it block), hoặc nhóm test (describe).

Như thế này:

describe Github, :vcr do
  # ...
end

Điều này sẽ tạo file cassette được đặt tên theo mô tả test:

spec/vcr/
└── Github
    ├── can_parse_user_data.yml
    └── can_test_vcr.yml

Chú ý rằng điều này sẽ tạo một cassette cho mỗi test…

Ngay cả khi hai test tạo request giống nhau & dùng dữ liệu giống nhau. VCR sẽ tạo cassette riêng cho chúng.

Các tùy chọn & Mẹo VCR hữu ích

Nếu bạn gặp vấn đề với cassette, hoặc muốn phiên bản dữ liệu mới, bạn có thể xóa file cassette.

VCR sẽ ghi lại response API mới & điều đó có thể giải quyết vấn đề.

Nhưng nếu không?

Bạn có thể bật debug mode trong VCR.configure:

VCR.configure do |c|
  # ...
  c.debug_logger = $stderr
end

Điều này có thể tạo ra nhiều output, nên hãy giới hạn test chỉ những cái bạn quan tâm.

Tiếp theo:

Giả sử có API keys, hoặc dữ liệu nhạy cảm khác như một phần của response API…

Bạn có thể muốn lọc dữ liệu đó khỏi bản ghi.

Cách làm:

VCR.configure do |c|
  # ...
  c.define_cassette_placeholder("<API_KEY>", ENV["API_KEY"])
end

Tóm tắt

Bạn đã học cách dùng gem WebMock & VCR để viết test cho ứng dụng Ruby mà không phải chờ đợi phản hồi API bên ngoài!

Làm chủ VCR trong Ruby: Tăng hiệu suất & Độ tin cậy Test

Nếu bạn thích điều này, đừng quên chia sẻ bài viết này để nhiều người hơn có thể thưởng thức.

Cảm ơn bạn đã đọc 🙂