O único HTTP que esta aplicação faz
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 |
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
FetchSiteIconServicerecebe 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
:testdo Action Mailer. - A pergunta organizadora é em qual camada você corta o fio, porque isso decide quanto código continua testado.
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.