O único HTTP que esta aplicação faz

Prévia grátis 4 min de leitura

Antes de aprender ferramentas para simular HTTP de saída, vale saber quanto HTTP de saída existe. Neste repositório, uma busca por todo cliente HTTP devolve dois arquivos.

$ grep -rln "Net::HTTP\|Faraday\|HTTParty\|RestClient\|URI.open" app/ lib/
app/services/partners/fetch_site_icon_service.rb
app/services/partners/webhook_transport.rb

Dois pontos que fazem HTTP, mais um fluxo OAuth por uma gem, mais e-mail de saída. Quatro integrações numa aplicação de 204 arquivos de spec, o que é normal. E é por isso que "como lidamos com serviços externos nos testes" costuma ser uma pergunta menor do que soa.

Quais são as quatro

Partners::FetchSiteIconService. Dada a URL de um parceiro, ele busca a página, lê as tags <link rel="icon"> e apple-touch-icon, escolhe a maior, baixa e anexa como logo do parceiro.

def self.call(partner:, http: Net::HTTP)
  new(partner, http).call
end

Leia a assinatura. O cliente HTTP é um parâmetro com um padrão.

Partners::WebhookTransport. Um adaptador fino de Net::HTTP que posta um evento assinado no endpoint de um parceiro, com timeouts de cinco segundos, levantando DeliveryError em qualquer resposta fora de 2xx para o job poder tentar de novo. Ele existe como módulo próprio para o job de entrega ser testado sem a rede.

OAuth do GitHub, pela omniauth-github:

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :github, ENV["GITHUB_KEY"], ENV["GITHUB_SECRET"], scope: "user:email"
end

E-mail de saída, pelo Action Mailer e SMTP.

Por que a rede não pode estar na suíte

Um teste que faz uma requisição real é pior de quatro maneiras separadas, e elas se somam:

Ele é instável. O serviço está fora, te limita por taxa, ou está lento hoje de manhã. O teste falha e nada no seu código mudou, o que ensina todo mundo a rerodar a suíte em vez de ler a falha.

Ele é lento. Uma ida e volta de rede são dezenas ou centenas de milissegundos contra os cerca de 0,05ms que uma consulta local ao banco custa. Um teste de integração pode dominar uma suíte.

Ele não é repetível. A resposta muda. Um teste afirmando sobre os dados de hoje falha amanhã.

Ele tem efeitos colaterais. Um teste que faz POST num serviço real cria registros reais, envia mensagens reais, ou gasta dinheiro real.

flowchart TB
  T["um spec que faz uma requisição real"] --> A["instável: o serviço, não seu código"]
  T --> B["lento: dezenas de ms, ou um timeout"]
  T --> C["não repetível: a resposta muda"]
  T --> D["efeitos colaterais: registros reais, dinheiro real"]
  A --> R["a suíte deixa de ser evidência"]
  B --> R
  C --> R
  D --> R

Como este repositório trata cada uma

Quatro integrações, quatro técnicas, e nenhuma delas é WebMock ou VCR:

Integração Técnica Onde
Busca do ícone do site O cliente HTTP é injetado; o spec passa uma classe falsa fetch_site_icon_service_spec.rb
Webhooks de parceiros O spec do job simula WebhookTransport.post com mocks do RSpec; o adaptador em si não tem spec deliver_webhook_job_spec.rb
OAuth do GitHub OmniAuth.config.test_mode = true e mock_auth[:github] omniauth_callbacks_spec.rb
E-mail O método de entrega :test do Action Mailer Padrão do Rails

Esse é um conjunto de escolhas deliberadas e não um descuido. E o resto deste curso é sobre quando cada uma é certa e o que as duas ferramentas que todos buscam acrescentam.

A pergunta por baixo

Toda técnica aqui responde uma pergunta: em qual camada você corta o fio?

Você pode substituir o objeto que faz a chamada, pedir para a biblioteca fingir, interceptar o HTTP na fronteira do socket, ou reproduzir uma resposta real gravada antes. Cada corte está numa profundidade diferente, e a profundidade determina quanto do seu código ainda está sendo testado.

Esse enquadramento é a aula 2, e é mais útil que qualquer uma das ferramentas.

Pontos-chave

  • Esta aplicação faz HTTP de saída de dois lugares (ícones de site e webhooks de parceiros), mais OAuth e e-mail.
  • Chamadas reais de rede numa suíte são instáveis, lentas, não repetíveis e com efeitos colaterais: quatro razões independentes.
  • O FetchSiteIconService recebe o cliente HTTP como parâmetro: http: Net::HTTP.
  • As quatro integrações usam quatro técnicas: injeção, um adaptador simulado, o modo de teste da biblioteca, e a entrega :test do Action Mailer.
  • A pergunta organizadora é em qual camada você corta o fio, porque isso decide quanto código continua testado.
Aula 1 de 7 · grátis

Continue com a aula 2

Quatro lugares para cortar o fio

Compara quatro pontos de corte (falsa injetada, modo de teste, WebMock e VCR) e o que cada um prova.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...