Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing APIs

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Testing APIs

Avatar for Rodrigo Flores

Rodrigo Flores

May 27, 2013
Tweet

More Decks by Rodrigo Flores

Other Decks in Programming

Transcript

  1. O que preciso da API ? Preciso autenticar ? Preciso

    pegar uma lista com as informações de algum lugar ? Monday, May 27, 13
  2. Multi-ambiente Em desenvolvimento a API deve funcionar mas não ter

    efeitos Em teste, a API não deve funcionar (nem fazer as requests) Em produção, deve funcionar Monday, May 27, 13
  3. require 'net/http' require 'json' uri = URI.parse('https://api.github.com/users/ rodrigoflores/repos') http =

    Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri.request_uri) response = http.request(request) repos = JSON.parse(response.body) repos.each do |repo| puts repo['name'] end Monday, May 27, 13
  4. # encoding: utf-8 require 'net/http' require 'json' require 'webmock' include

    WebMock::API stub_request(:get, "https://api.github.com/users/rodrigoflores/ repos").to_return(body: File.read('response.json')) uri = URI.parse('https://api.github.com/users/rodrigoflores/repos') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri.request_uri) response = http.request(request) repos = JSON.parse(response.body) repos.each do |repo| puts repo['name'] end Monday, May 27, 13
  5. Real HTTP connections are disabled. Unregistered request: GET https:// api.github.com/users/rodrigoflores/repos

    with headers {'Accept'=>'*/*', 'User-Agent'=>'Ruby'} (WebMock::NetConnectNotAllowedError) You can stub this request with the following snippet: stub_request(:get, "https://api.github.com/users/rodrigoflores/repos"). with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}). to_return(:status => 200, :body => "", :headers => {}) registered request stubs: stub_request(:get, "https://api.github.com/users/josevalim/repos") Não “stuba” o Net::HTTP Monday, May 27, 13
  6. 1a Vez: Faz o Request e serializa o request/response 2..n

    vez: Reproduz o que foi serializado Monday, May 27, 13
  7. uri = URI.parse('https://api.github.com/users/ rodrigoflores/repos') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl =

    true request = Net::HTTP::Get.new(uri.request_uri) VCR.use_cassette('repos') do response = http.request(request) repos = JSON.parse(response.body) repos.each do |repo| puts repo['name'] end end Monday, May 27, 13
  8. --- http_interactions: - request: method: get uri: https://api.github.com/users/rodrigoflores/repos body: encoding:

    US-ASCII string: "" headers: Accept: - "*/*" User-Agent: - Ruby response: # (...) recorded_at: Sat, 25 May 2013 13:59:28 GMT recorded_with: VCR 2.5.0 Monday, May 27, 13
  9. response: status: code: 200 message: OK headers: #(...) body: encoding:

    ASCII-8BIT string: "[{\"id\":1254869,\"name\":\"1001\",\"full_name\": \"rodrigoflores" # (...) Monday, May 27, 13
  10. require 'net/http' require 'json' require 'faraday' require 'faraday_middleware' conn =

    Faraday.new(:url => 'https://api.github.com') do |faraday| faraday.adapter Faraday.default_adapter faraday.response :json, :content_type => /\bjson$/ end repos = conn.get('/users/rodrigoflores/repos').body repos.each do |repo| puts repo['name'] end Monday, May 27, 13
  11. require 'net/http' require 'json' require 'faraday' require 'faraday_middleware' conn =

    Faraday.new(:url => 'https://api.github.com') do |faraday| faraday.adapter :test do |stub| stub.get('/users/rodrigoflores/repos') {[ 200, { 'Content-Type' => 'application/json; charset=utf-8' }, File.read('response.json') ]} end faraday.response :json, :content_type => /\bjson$/ end repos = conn.get('/users/rodrigoflores/repos').body repos.each do |repo| puts repo['name'] end Monday, May 27, 13
  12. Decidir qual o melhor jeito de testar Testar o cliente

    como uma aplicação Ruby Tomar cuidado para não fazer requests em teste (pelo menos não o tempo todo) Testes de contrato podem valer a pena ou não Monday, May 27, 13
  13. class ExampleController < ApplicationController def index expires_in 10.minutes, public: true

    render json: { version: '3.2.19' } end end Monday, May 27, 13
  14. describe ExampleController do describe "GET #index" do it "shows the

    version info" do get :index parsed_response = JSON.parse(response.body) parsed_response['version'].should == '3.2.19' end it "has a max-age of 10 minutes" do get :index response.headers['Cache-Control'].should == "max-age=600, public" end it 'has a 200 status' do get :index response.status.should == 200 end end end Monday, May 27, 13
  15. Testar com testes de controller Testar headers e status code

    (quando forem relevantes) Manter documentação (com testes parece ser mais simples) Monday, May 27, 13