In the article [Ruby] Procedure for creating an external API linkage class using Faraday, we introduced how to link with an external API using Faraday.
In logic test code that uses an external API, it is common to stub HTTP requests instead of using the actual API. In Rails, you can stub HTTP requests by using a gem called webmock.
This time, I will introduce how to use WebMock to create logic test code linked with an external API.
This time, we will create a test code for a class called QiitaClientAPI
that works with the Qiita API.
The class implements a method called get_items
to get a list of articles from Qiita.
The specific source code is as follows.
lib/qiita_api_client.rb
class QiitaApiClient
class HTTPError < StandardError
def initialize(message)
super "connection failed: #{message}"
end
end
class << self
def connection
Faraday::Connection.new('https://qiita.com') do |builder|
builder.authorization :Bearer, "#{Rails.application.credentials.qiita[:token]}"
builder.request :url_encoded #URL-encode request parameters
builder.response :logger #Output the response to standard output
builder.adapter Faraday.default_adapter #Adapter selection. The default is Net::HTTP
builder.response :json, :content_type => "application/json" #JSON parse the response body
end
end
def get_items
begin
response = connection.get(
'/api/v2/items'
)
response.body
rescue Faraday::ConnectionFailed => e
raise QiitaApiClient::HTTPError.new(e.message)
end
end
end
end
Prepare to run the test code.
This time we will use RSpec as the testing framework. Add rspec-rails to your Gemfile.
Gemfile
group :development, :test do
gem 'rspec-rails'
end
Install gem and set up RSpec.
$ bundle install
$ rails generate rspec:install
Add webmock to your Gemfile and install it.
Gemfile
gem 'webmock'
$ bundle install
Below, we will introduce how to write test code using WebMock.
The normal test code is as follows.
spec/lib/qiita_api_client_spec.rb
require 'rails_helper'
describe 'QiitaApiClient' do
before do
WebMock.enable! #Enable WebMock
allow(Rails.application.credentials).to receive(:qiita).and_return({token: '123'})
end
describe '.get_items' do
let(:response_body) { [{ "title": "test" }].to_json }
before do
WebMock.stub_request(:get, "https://qiita.com/api/v2/items").
with(
headers: {'Authorization' => "Bearer 123"}
).
to_return(
body: response_body,
status: 200,
headers: { 'Content-Type' => 'application/json' }
)
end
it 'Data can be obtained' do
expect(QiitaApiClient.get_items).to eq(JSON.parse(response_body))
end
end
end
I have enabled WebMock with WebMock.enable!
and created an HTTP request stub at WebMock.stub_request
.
By using WebMock, you can describe the behavior of "what kind of request is returned and what kind of response is returned". This allows you to create a simulated situation where data is exchanged via an external API.
In addition, the part of allow (Rails.application.credentials)
described in before
sets a dummy value for Rails.application.credentials.qiita [: token]
described in the application code. Is for.
If the application code cannot communicate normally with the external API, it raises the exception QiitaApiClient :: HTTPError
with an error message.
The test code of the abnormal system that confirms that the exception has occurred is as follows.
spec/lib/qiita_api_client_spec.rb
require 'rails_helper'
describe 'QiitaApiClient' do
before do
WebMock.enable!
allow(Rails.application.credentials).to receive(:qiita).and_return({token: '123'})
end
describe '.get_items' do
let(:response_body) { { "message": "error_message", "type": "error_type" }.to_json }
before do
WebMock.stub_request(:get, "https://qiita.com/api/v2/items").
to_raise(Faraday::ConnectionFailed.new("some error"))
end
it 'Exception is raised' do
#Exception test is expect()Not expect{}So be careful
expect{QiitaApiClient.get_items}.to raise_error(QiitaApiClient::HTTPError, "connection failed: some error")
end
end
end
I have created a stub that raises an exception with to_raise
in WebMock and confirmed that the exception is raised with raise_error
in expect.
The final test code that summarizes the normal system and abnormal system introduced this time is as follows.
spec/lib/qiita_api_client_spec.rb
require 'rails_helper'
describe 'QiitaApiClient' do
let(:qiita_base_uri) { 'https://qiita.com/api/v2' }
before do
WebMock.enable!
allow(Rails.application.credentials).to receive(:qiita).and_return({token: '123'})
end
describe '.get_items' do
subject { QiitaApiClient.get_items }
context 'success' do
let(:response_body) { [{ "title": "test" }].to_json }
before do
WebMock.stub_request(:get, "#{qiita_base_uri}/items").
with(
headers: {'Authorization' => "Bearer 123"}
).
to_return(
body: response_body,
status: 200,
headers: { 'Content-Type' => 'application/json' }
)
end
it 'Data can be obtained' do
expect(subject).to eq(JSON.parse(response_body))
end
end
context 'Failure' do
before do
WebMock.stub_request(:get, "#{qiita_base_uri}/items").
to_raise(Faraday::ConnectionFailed.new("some error"))
end
it 'Exception is raised' do
expect{subject}.to raise_error(QiitaApiClient::HTTPError, "connection failed: some error")
end
end
end
end
We will introduce how to use WebMock to create logic test code linked with an external API.
The flow of the test code using WebMock is as follows.
I'm on Twitter (@ nishina555). I hope you will follow me!
Recommended Posts