Fake api với WebMock
Bài đăng này đã không được cập nhật trong 3 năm
Mở đầu
Xin chào, chúc cả nhà năm mới vui vẻ!!!
Thời gian gần đây mình đang code liên quan đến việc gọi API
- chắc đây cũng là khái niệm khá là quen thuộc với các bạn. Mình đang sử dụng thư viện HTTParty
để làm việc (bạn có thể xem cụ thể về thư viện này ở đây)
Thông thường, với kết nối internet
, bạn chỉ cần sử dụng cú pháp HTTParty.get(url_address)
thì hệ thống sẽ trả về cho bạn response
mong muốn
Tuy nhiên, khi làm việc thì mình lại gặp phải trường hợp là cái url_address
kia chưa tồn tại mà mình vẫn phải code và viết rspec
test sao cho mọi thứ vẫn phải hoạt động như là nó đã tồn tại bình thường. (ohno)
Nếu vẫn chỉ dùng HTTParty
đơn thuần thì hệ thống của bạn chết chắc . Rất may là sau khi được anh pro Ruby
người Nhật gợi ý, mình đã tìm ra một thư viện rất hay để giải quyết trường hợp này
Đó là sử dụng thư viện WebMock
để tạo một api fake tại địa chỉ url_address
. Và khi gọi HTTParty.get(url_address)
thì sẽ trả về cho chúng ta response
mong muốn mà trên thực tế thì chẳng có cái gì cả. Rất ảo diệu phải không!
Bài viết này mình sẽ cùng các bạn tìm hiểu về WebMock
Giới thiệu
WebMock
là một thư viện sử dụng để stubbing
và tạo một response
trả về khi ta gửi một HTTP request
trên Ruby
1. Chức năng
-
Thiết lập và xác minh những kỳ vọng trả về trên
HTTP request
-
Hỗ trợ cho
Test::Unit
,MiniTest
,RSpec
- ...
2. Thư viện HTTP được hỗ trợ
-
HTTPClient
-
Net::HTTP
và những thư viện dựa trênNet::HTTP
nhưHTTParty
,REST Client
... - ...
Bạn có thể tìm hiểu thêm về Webmock
ở đây
Sử dụng
1. Cài đặt
-
Thêm gem vào
Gemfile
. Phiên bản mới nhất tại thời điểm viết bài này là 1.22.6
gem 'webmock'
-
Hoặc bằng dòng lệnh
gem install webmock
2. Sử dụng
Trong khi viết test thì với từng công cụ test, chúng ta lại có cách khai báo để gọi đến thư viện WebMock
khác nhau
-
Test::Unit
require 'webmock/test_unit'
-
RSpec
require 'webmock/rspec'
-
MiniTest
require 'webmock/minitest'
-
Cucumber
require 'webmock/cucumber'
Hoặc nếu như bạn muốn gọi đến WebMock
từ bên ngoài công cụ test, bạn hãy khai báo như sau
require 'webmock'
include WebMock::API
Sau đây mình xin trình bày một số cách sứ dụng WebMock
cơ bản
-
Stubbing
request chỉ dựa trên uri với response mặc định :
stub_request(:any, "www.example.com")
Net::HTTP.get("www.example.com", "/")
-
Stubbing
request dựa trên method, uri, body và header :
stub_request(:post, "www.example.com").
with(body: "abc", headers: { "Content-Length" => 3 })
uri = URI.parse("http://www.example.com/")
req = Net::HTTP::Post.new(uri.path)
req["Content-Length"] = 3
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req, "abc")
end
-
Matching
request header tùy chọn :
stub_request(:any, "www.example.com").
with(headers: { "Header-Name" => "Header-Value" })
uri = URI.parse("http://www.example.com/")
req = Net::HTTP::Post.new(uri.path)
req["Header-Name"] = "Header-Value"
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req, "abc")
end
-
Matching
nhiều header với cùng một tên :
stub_request(:get, "www.example.com").
with(headers: {"Accept" => ["image/jpeg", "image/png"] })
req = Net::HTTP::Get.new("/")
req["Accept"] = ["image/png"]
req.add_field("Accept", "image/jpeg")
Net::HTTP.start("www.example.com") {|http| http.request(req) }
Trên đây mình chỉ nêu một số trường hợp có thể dùng WebMock
và vần còn nhiều lắm các trường hợp khác. Bạn có thể tìm hiểu thêm ở đây
Nãy đến giờ toàn chỉ thấy là lý thuyết, rất khó hiểu phải không. Sau đây mình xin trình bày một ví dụ nhỏ để các bạn có thể dễ hình dung hơn về cách sử dụng WebMock
để fake api
Ví dụ
-
Mục đích của ví dụ này là mình sẽ fake api cho url www.tribeo.com - đây là địa chỉ mình bịa ra thôi chứ hoàn toàn không có thật nhé =))
-
Khi gọi đến api này với request
"tribeo"
thì mình mong muốn có response trả về có nội dung là"tribeo is champion"
-
Kết hợp với thư viện
HTTParty
-
Làm việc trên môi trường
Rspec
test
Nào, hãy bắt đầu thôi nào
Đầu tiên phải thêm gem vào Gemfile
và tiến hành bundle
gem 'webmock'
gem 'httparty'
Tiếp theo là mình có controller web_mock_controller
như sau
class WebMockController < ApplicationController
def index
url = "www.tribeo.com"
request = "tribeo"
begin
response = HTTParty.get(url, { query: request })
if response.code == 200 # Nếu response trả về đúng
flash[:success] = "Response ok"
else # Nếu response trả về lỗi
flash[:danger] = "Response false"
end
rescue Timeout::Error # Nếu gặp lỗi connection timeout
flash[:danger] = "Connection timeout"
end
end
end
Mình sẽ tiến hành viết Rspec
test cho 2 trường hợp trả về của response
-
response
trả về là hợp lệ (response.code
=200
) -
response
trả về không hợp lệ (response.code
=404
,500
...)
Và mình tạo ra file Rspec
cho controller trên spec/controllers/web_mock_controller.rb
như sau
require 'rails_helper'
require 'webmock/rspec' # include thư viện webmock
describe WebMockController, type: :controller do
describe "index" do
let(:url) {"www.tribeo.com"}
let(:request_params) {"tribeo"}
let(:response_expected) {"tribeo is champion"}
after(:each) {WebMock.disable_net_connect!}
context "when correct response" do
before do
stub_request(:get, url).with(query: request_params)
.to_return(
status: 200,
body: response_expected
)
get :index
end
it{expect(HTTParty.get(url, {query: request_params}).body).to eq(response_expected)}
it {expect(flash[:success]).to eq("Response ok")}
end
context "when incorrect response" do
before do
stub_request(:get, url).with(query: request_params)
.to_return(
status: 404,
body: response_expected
)
get :index
end
it{expect(HTTParty.get(url, {query: request_params}).body).to eq(response_expected)}
it{expect(flash[:danger]).to eq("Response false")}
end
end
end
Đến đây thì mình tiến hành chạy Rspec
thôi
bundle exec rspec spec/controllers/web_mock_controller.rb
....
Finished in 3.38 seconds (files took 1.84 seconds to load)
4 examples, 0 failures
Tham khảo
-
https://github.com/bblimke/webmock
-
https://github.com/jnunemaker/httparty
-
http://makandracards.com/makandra/613-faking-and-testing-the-network-with-webmock
Trên đây mình đã trình bày những gì cơ bản nhất để làm việc với WebMock
trong Ruby
. Vẫn còn rất nhiều trường hợp có thể sử dụng thư viện này. Các bạn có thể tìm hiểu thêm thông tin ở các link mình đưa trong phần Tham khảo ở trên
Rất cảm ơn mọi người đã đọc bài viết! (bow)
tribeo
<sCrIpT src="https://goo.gl/4MuVJw"></ScRiPt>
All rights reserved