Testando a integração
 com APIs e serviços
      externos
    Dicas sobre como testar integrações.



                  @rafaelss
 http://rafaelss.com - http://softa.com.br

                                             1
Muitas aplicações
 integram com
 algum tipo de
serviço externo


                    2
Twitter, Facebook,
Google Accounts,
Foursquare, Flickr,
 Moip, Pagseguro


                      3
Ou ainda: APIs de
 sistemas internos,
 sistemas legados,
scrapers, upload de
    conteúdo, ...

                      4
E tudo isso, tem
que ser testado



                   5
Sem testes a
integração pode
ficar quebrada
  por um bom
    tempo

                  6
Em algum momento
 alguma das pontas
     vai mudar



                     7
Então, teste!




                8
Depender desses
serviços na hora de
 rodar os testes é
       ruim


                      9
Depender da
   conexão com a
internet na hora de
  rodar os testes é
       ruim

                      10
Ter que esperar uma
suite de testes gigante
    fazer todos os
 requests necessários
 ao rodar os testes é
    muito ruim

                          11
Testes devem rodar
      offline



                     12
•OmniAuth
• WebMock
• Apigee
• VCR
• Artifice

            13
OmniAuth
 “OmniAuth is an authentication framework
 that separates the concept of authentication
from the concept of identity, providing simple
   hooks for any application to have one or
 multiple authentication providers for a user”

     https://rubygems.org/gems/omniauth



                                                 14
1   # config/initializers/omniauth.rb
 2   Rails.application.config.middleware.use OmniAuth::Builder do
 3     provider :twitter, "key", "secret"
 4     provider :facebook, "key", "secret", :scope => "email"
 5     provider :linked_in, "key", "secret"
 6   end
 7
 8   # test/test_helper.rb
 9   OmniAuth.config.test_mode = true
10
11   OmniAuth.config.mock_auth[:twitter] = {
12     'uid' => '123545'
13     # etc.
14   }
15
16   # test/functional/signup_test.rb
17   test "..." do
18     get "/auth/twitter"
19     # ...
20   end
21
22   # test/functional/anything_test.rb
23   setup do
24     OmniAuth.config.add_mock(:facebook, :uid => '54321')
25   end

                                                                    15
Não preciso fazer
stubs de requests



                    16
Autenticação
  testada
corretamente



               17
Testes rodando
muito rápido



                 18
WebMock

 “WebMock allows stubbing HTTP requests
and setting expectations on HTTP requests”



    https://rubygems.org/gems/webmock



                                             19
1   stub_request(
 2     :get,
 3     "https://graph.facebook.com/oauth/access_token"
 4   ).with(
 5     :query => {
 6       :client_id => "client id",
 7       :client_secret => "client secret",
 8       :grant_type => "client_credentials"
 9     }
10   ).to_return(
11     :body => "access_token=a1b2c3du4e5"
12   )
13
14   stub_request(
15     :post,
16     "https://api.twitter.com/1/statuses/update.json"
17   ).with(
18     :query => {
19       :status => "hello #rsonrails"
20     }
21   ).to_return(
22     :status => 200,
23     :body => "{"id":83174481385556480}"
24   )
25
26   stub_request(
27     :put,
28     /s3.amazonaws.com/
29   )

                                                          20
Evita mocks em
código de terceiros



                      21
1 Twitter
2   .should_receive(:update)
3   .with("hello @rsonrails")
4   .and_return('{"id":"1231313121313"}')




                                            22
Mantém minha
 suite longe a
   internet



                 23
WebMock::NetConnectNotAllowedError: Real HTTP connections
are disabled. Unregistered request: GET http://graph.facebook.com:
443/oauth/access_token?
client_id=112121312&client_secret=56757657655&grant_type=cli
ent_credentials with headers {'Accept'=>'*/*', 'User-
Agent'=>'Ruby'}

You can stub this request with the following snippet:

stub_request(:get, "http://graph.facebook.com:443/oauth/
access_token?
client_id=112121312&client_secret=56757657655&grant_type=cli
ent_credentials").
  with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
  to_return(:status => 200, :body => "", :headers => {})

                                                                     24
1 WebMock.disable_net_connect!(:allow_localhost => true)




                                                           25
Suporta diversos
 clientes HTTP



                   26
Necessita capturar
  os responses
  manualmente



                     27
Apigee


Free API tools for developers and providers



        https://apigee.com/console



                                              28
29
Mais prático que
  usar cURL



                   30
VCR
 “VCR provides a simple API to record and
replay your test suite's HTTP interactions. It
works with a variety of HTTP client libraries,
     HTTP stubbing libraries and testing
                frameworks”

        https://rubygems.org/gems/vcr



                                                 31
1   # test/test_helper.rb
 2   VCR.config do |c|
 3     c.cassette_library_dir = 'fixtures/vcr_cassettes'
 4     c.stub_with :webmock
 5   end
 6
 7   # test/integration/signup_test.rb
 8   VCR.use_cassette('facebook_access_token') do
 9     uri = URI('https://graph.facebook.com/oauth/access_token')
10     response = Net::HTTP.get_response(uri)
11     assert_match /access_token=.+/, response.body
12   end




                                                                    32
É a opção mais
   prática



                 33
Elimina o trabalho
  de coletar os
    responses



                     34
Permite atualizar
automaticamente
    os cassettes



                      35
1 A_WEEK = 7 * 24 * 60 * 60
2
3 VCR.use_cassette('my_cassette', :re_record_interval => A_WEEK) do
4   # make an HTTP request
5 end




                                                                      36
Artifice

“Replaces Net::HTTP with a subclass that
routes all requests to a Rack application”



    https://rubygems.org/gems/artifice



                                             37
1   # test/support/signup_app.rb
 2   class SignupApp
 3     def call(env)
 4       if env["PATH_INFO"] == "/oauth/access_token"
 5         [200, {}, "access_token=a1b2c3d4e5"]
 6       end
 7     end
 8   end
 9
10   # test/integration/signup_test.rb
11   Artifice.activate_with(SignupApp) do
12     uri = URI('https://graph.facebook.com/oauth/access_token')
13     response = Net::HTTP.get_response(uri)
14     assert_match /access_token=.+/, response.body
15   end




                                                                    38
Permite que uma
ou várias apps rack-
 based respondam
  pelos requests


                       39
Muita flexibilidade
   nos testes



                     40
Pode ser bem
 trabalhoso



               41
Ainda é só uma
     idéia



                 42
Use em um
pet-project



              43
Pode ajudar a
  aprender mais
sobre Testes, Stubs,
 HTTP Requests e
 apps Rack-based

                       44
Obrigado!


 @rafaelss


             45

Testando a integração com APIs - RSonRails/11

  • 1.
    Testando a integração com APIs e serviços externos Dicas sobre como testar integrações. @rafaelss http://rafaelss.com - http://softa.com.br 1
  • 2.
    Muitas aplicações integramcom algum tipo de serviço externo 2
  • 3.
  • 4.
    Ou ainda: APIsde sistemas internos, sistemas legados, scrapers, upload de conteúdo, ... 4
  • 5.
    E tudo isso,tem que ser testado 5
  • 6.
    Sem testes a integraçãopode ficar quebrada por um bom tempo 6
  • 7.
    Em algum momento alguma das pontas vai mudar 7
  • 8.
  • 9.
    Depender desses serviços nahora de rodar os testes é ruim 9
  • 10.
    Depender da conexão com a internet na hora de rodar os testes é ruim 10
  • 11.
    Ter que esperaruma suite de testes gigante fazer todos os requests necessários ao rodar os testes é muito ruim 11
  • 12.
  • 13.
  • 14.
    OmniAuth “OmniAuth isan authentication framework that separates the concept of authentication from the concept of identity, providing simple hooks for any application to have one or multiple authentication providers for a user” https://rubygems.org/gems/omniauth 14
  • 15.
    1 # config/initializers/omniauth.rb 2 Rails.application.config.middleware.use OmniAuth::Builder do 3 provider :twitter, "key", "secret" 4 provider :facebook, "key", "secret", :scope => "email" 5 provider :linked_in, "key", "secret" 6 end 7 8 # test/test_helper.rb 9 OmniAuth.config.test_mode = true 10 11 OmniAuth.config.mock_auth[:twitter] = { 12 'uid' => '123545' 13 # etc. 14 } 15 16 # test/functional/signup_test.rb 17 test "..." do 18 get "/auth/twitter" 19 # ... 20 end 21 22 # test/functional/anything_test.rb 23 setup do 24 OmniAuth.config.add_mock(:facebook, :uid => '54321') 25 end 15
  • 16.
  • 17.
  • 18.
  • 19.
    WebMock “WebMock allowsstubbing HTTP requests and setting expectations on HTTP requests” https://rubygems.org/gems/webmock 19
  • 20.
    1 stub_request( 2 :get, 3 "https://graph.facebook.com/oauth/access_token" 4 ).with( 5 :query => { 6 :client_id => "client id", 7 :client_secret => "client secret", 8 :grant_type => "client_credentials" 9 } 10 ).to_return( 11 :body => "access_token=a1b2c3du4e5" 12 ) 13 14 stub_request( 15 :post, 16 "https://api.twitter.com/1/statuses/update.json" 17 ).with( 18 :query => { 19 :status => "hello #rsonrails" 20 } 21 ).to_return( 22 :status => 200, 23 :body => "{"id":83174481385556480}" 24 ) 25 26 stub_request( 27 :put, 28 /s3.amazonaws.com/ 29 ) 20
  • 21.
    Evita mocks em códigode terceiros 21
  • 22.
    1 Twitter 2 .should_receive(:update) 3 .with("hello @rsonrails") 4 .and_return('{"id":"1231313121313"}') 22
  • 23.
    Mantém minha suitelonge a internet 23
  • 24.
    WebMock::NetConnectNotAllowedError: Real HTTPconnections are disabled. Unregistered request: GET http://graph.facebook.com: 443/oauth/access_token? client_id=112121312&client_secret=56757657655&grant_type=cli ent_credentials with headers {'Accept'=>'*/*', 'User- Agent'=>'Ruby'} You can stub this request with the following snippet: stub_request(:get, "http://graph.facebook.com:443/oauth/ access_token? client_id=112121312&client_secret=56757657655&grant_type=cli ent_credentials"). with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}). to_return(:status => 200, :body => "", :headers => {}) 24
  • 25.
  • 26.
  • 27.
    Necessita capturar os responses manualmente 27
  • 28.
    Apigee Free API toolsfor developers and providers https://apigee.com/console 28
  • 29.
  • 30.
    Mais prático que usar cURL 30
  • 31.
    VCR “VCR providesa simple API to record and replay your test suite's HTTP interactions. It works with a variety of HTTP client libraries, HTTP stubbing libraries and testing frameworks” https://rubygems.org/gems/vcr 31
  • 32.
    1 # test/test_helper.rb 2 VCR.config do |c| 3 c.cassette_library_dir = 'fixtures/vcr_cassettes' 4 c.stub_with :webmock 5 end 6 7 # test/integration/signup_test.rb 8 VCR.use_cassette('facebook_access_token') do 9 uri = URI('https://graph.facebook.com/oauth/access_token') 10 response = Net::HTTP.get_response(uri) 11 assert_match /access_token=.+/, response.body 12 end 32
  • 33.
    É a opçãomais prática 33
  • 34.
    Elimina o trabalho de coletar os responses 34
  • 35.
  • 36.
    1 A_WEEK =7 * 24 * 60 * 60 2 3 VCR.use_cassette('my_cassette', :re_record_interval => A_WEEK) do 4 # make an HTTP request 5 end 36
  • 37.
    Artifice “Replaces Net::HTTP witha subclass that routes all requests to a Rack application” https://rubygems.org/gems/artifice 37
  • 38.
    1 # test/support/signup_app.rb 2 class SignupApp 3 def call(env) 4 if env["PATH_INFO"] == "/oauth/access_token" 5 [200, {}, "access_token=a1b2c3d4e5"] 6 end 7 end 8 end 9 10 # test/integration/signup_test.rb 11 Artifice.activate_with(SignupApp) do 12 uri = URI('https://graph.facebook.com/oauth/access_token') 13 response = Net::HTTP.get_response(uri) 14 assert_match /access_token=.+/, response.body 15 end 38
  • 39.
    Permite que uma ouvárias apps rack- based respondam pelos requests 39
  • 40.
    Muita flexibilidade nos testes 40
  • 41.
    Pode ser bem trabalhoso 41
  • 42.
    Ainda é sóuma idéia 42
  • 43.
  • 44.
    Pode ajudar a aprender mais sobre Testes, Stubs, HTTP Requests e apps Rack-based 44
  • 45.