Como testar uma Rails API com Rspec

 

Primeiramente, será apresentado como criar uma API Rest usando Rails 5.0 a partir da API de clima disponível no site https://openweathermap.org/api. Em seguida, será instalado o pacote RSpec de Rails para que seja possível executar os testes dessa API.

Pré-requisitos

Criando uma API Rest com Ruby on Rails

Para criar uma API com Rails é necessário que seja feita a instalação completa do Rails 5.0 na sua máquina.

No terminal entrar na pasta do seu workspace e digitar o comando para criar um novo projeto de API em rails:

C:/workspace>rails new climateapi --api
Observe que esse projeto difere dos outros projetos por haver o termo ‘api

Com a aplicação criada, entrar na pasta do projeto criado e digitar o comando para instalar todas as bibliotecas do projeto.

C:/workspace/climateapi>bundle install
Caso ocorra algum erro referente ao sqlite, basta alterar no arquivo /climateapi/Gemfile.
gem 'sqlite3', '< 1.4'
gem 'rack-cors'

Em seguida, executar novamente o comando ‘bundle install’.

Na pasta config adicionar ao arquivo application.rb a configuração do Cors, que autoriza essa API ser utilizada por outros sistemas. 

#adicionar esse trecho do código
config.middleware.insert_before 0, "Rack::Cors" do .. end
require_relative 'boot'
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Climatempoapi
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Only loads a smaller set of middleware suitable for API only apps.
# Middleware like session, flash, cookies can be added back manually.
# Skip views, helpers and assets when generating a new resource.
config.api_only = true
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource(
'*',
headers: :any,
methods: [:get, :patch, :put, :delete, :post, :options]
)
end
end
end
end

Na pasta controllers /climateapi/app/controllers/api/v1 criar o arquivo clima_controller.rb

module Api
module V1
    class ClimaController < ApplicationController
def show
@host = 'http://api.openweathermap.org/data/2.5/'
@key = 'SUA_API_KEY'
city = params[:city]
@weather_city = api_request_city_weather(@host, city, @key)
puts @weather_city
render json: @weather_city
end
private
# GET API city weather from Open weather map
def api_request_city_weather(host, city, key)
require 'net/http'
require 'net/https'
require 'open-uri'
require 'json'
url_weather = host + 'weather?q=' + city + '&appid=' + key
uri = URI.parse(url_weather)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
response = http.request(request)
content = JSON.parse(response.body)
return content
end
end
end
end

Na pasta config /climateapi/config alterar o arquivo routes.rb

Rails.application.routes.draw do
namespace 'api' do
namespace 'v1' do
resources :weather, param: :city
end
end
end

Executar o comando no terminal para criar as rotas

C:/workspace/climateapi>rails routes
Controller#Action
api_v1_weather_index GET /api/v1/weather(.:format) api/v1/weather#index
POST /api/v1/weather(.:format) api/v1/weather#create
api_v1_weather GET /api/v1/weather/:city(.:format) api/v1/weather#show
PATCH /api/v1/weather/:city(.:format) api/v1/weather#update
PUT /api/v1/weather/:city(.:format) api/v1/weather#update
DELETE /api/v1/weather/:city(.:format) api/v1/weather#destroy

Em seguida, rodar a API para verificar se os dados em formato JSON foram recuperados da API Rest original.

C:/workspace/climateapi>rails s -b 0.0.0.0 -p 3050

Acessar a URL local no navegador e ver se exibe o resultado: http://localhost:3050/api/v1/weather/Aracaju

{
"coord": {
"lon": -37.07,
"lat": -10.91
},
"weather": [
{
"id": 802,
"main": "Clouds",
"description": "scattered clouds",
"icon": "03n"
}
],
"base": "stations",
"main": {
"temp": 298.15,
"feels_like": 299.58,
"temp_min": 298.15,
"temp_max": 298.15,
"pressure": 1012,
"humidity": 83
},
"visibility": 10000,
"wind": {
"speed": 4.6,
"deg": 100
},
"clouds": {
"all": 40
},
"dt": 1605072214,
"sys": {
"type": 1,
"id": 8322,
"country": "BR",
"sunrise": 1605081293,
"sunset": 1605126599
},
"timezone": -10800,
"id": 3471872,
"name": "Aracaju",
"cod": 200
}

Pronto! Sua API Rest em Ruby on Rails foi criada utilizando outro serviço de API disponível na internet.

Testando uma Rails API com Rspec

Agora que já temos uma Rails API criada, iremos instalar o rspec-rails e outras gems para que seja possível realizar os testes nessa API.

Abrir o arquivo Gemfile na raiz do mesmo projeto climateapi/Gemfile e incluir as seguintes gems na seção :test.

group :development, :test do

gem 'byebug', platform: :mri
gem 'rspec-rails', '~> 4.0.1'
gem 'factory_bot_rails'
end

Entrar na pasta do projeto criado e digitar o comando para instalar as novas bibliotecas do projeto.

C:/workspace/climateapi>bundle install

Em seguida executar o comando para geração da pasta climateapi/spec.

C:/workspace/climateapi>rails generate rspec:install

Entrar nessa pasta e criar um novo arquivo climateapi/spec/clima_spec.rb

require 'rails_helper'
describe "get weather route to Aracaju", :type => :request do
before {get '/api/v1/weather/Aracaju'}
it 'returns weather' do
expect(JSON.parse(response.body)['name']).to eq('Aracaju')
end
it 'returns status code 200' do
expect(response).to have_http_status(:success)
end
end

Em seguida, executar os testes utilizando o comando abaixo.

C:/workspace/climateapi>bundle exec rspec ./spec/weather_spec.rb

Observar que os testes passaram conforme o resultado esperado:

{"coord"=>{"lon"=>-37.07, "lat"=>-10.91}, "weather"=>[{"id"=>802, "main"=>"Clouds", 
"description"=>"scattered clouds", "icon"=>"03n"}], "base"=>"stations", 
"main"=>{"temp"=>298.15, "feels_like"=>299.58, "temp_min"=>298.15, "temp_max"=>298.15, 
"pressure"=>1012, "humidity"=>83}, "visibility"=>10000, "wind"=>{"speed"=>4.6, "deg"=>100}, 
"clouds"=>{"all"=>40}, "dt"=>1605073980, "sys"=>{"type"=>1, "id"=>8322, "country"=>"BR", 
"sunrise"=>1605081293, "sunset"=>1605126599}, "timezone"=>-10800, "id"=>3471872, 
"name"=>"Aracaju", "cod"=>200}


Finished in 1.55 seconds (files took 5.51 seconds to load)
2 examples, 0 failures

Fiz este artigo originalmente no Medium do GTSW:

https://medium.com/gtsw/como-testar-uma-rails-api-com-rspec-596d4ce39988