O teste quebrou. E não foi você.
Segunda de manhã, você abre o projeto e o CI tá vermelho.
Você não mexeu em nada desde sexta. Abre o log: o teste de integração com a API de pagamento falhou. Timeout.
O gateway deles teve uma instabilidade às 3 da manhã. Seu código tá perfeito. Mesmo assim, o build tá vermelho, o deploy travado, e agora você perde meia hora provando que o problema não é seu.
Já passou por isso? Teste que depende de API externa é assim: lento, instável e quebra por motivos que não são culpa sua. E tem o cenário pior — o teste que roda de verdade contra a API de pagamento, e a cada php artisan test você dispara 30 cobranças reais no sandbox até o gateway achar suspeito e bloquear.
O problema: seu teste não deveria conhecer a internet
Olha esse teste. Parece razoável, né?
public function test_busca_o_cep(): void
{
// isso bate no ViaCEP de VERDADE, toda vez que o teste roda
$endereco = $this->service->buscarCep('01001000');
$this->assertEquals('São Paulo', $endereco['cidade']);
}
O que tem de errado? Tudo que importa num teste:
- Lento — cada teste espera a ida e volta pela rede.
- Instável — a API cair, ficar lenta ou mudar o retorno quebra seu teste sem seu código ter mudado.
- Perigoso — se for uma API que cobra, envia e-mail ou cria pedido, você tá fazendo isso pra valer a cada execução.
- Sem controle — como você testa "o que acontece quando a API devolve erro 500"? Não dá pra pedir pra ela cair na hora certa.
O teste devia verificar o seu código. Não a saúde do servidor dos outros.
A solução: Http::fake() intercepta tudo
Aqui vem o $pedido->restore() dessa história. Se você usa o HTTP Client do Laravel (Http::get(), Http::post()...), uma linha resolve:
use Illuminate\Support\Facades\Http;
public function test_busca_o_cep(): void
{
// A partir daqui, NENHUMA requisição sai de verdade.
// Você diz o que cada URL deve responder.
Http::fake([
'viacep.com.br/*' => Http::response([
'localidade' => 'São Paulo',
'uf' => 'SP',
], 200),
]);
$endereco = $this->service->buscarCep('01001000');
$this->assertEquals('São Paulo', $endereco['cidade']);
}
Pronto. O Http::fake() intercepta a requisição e devolve a resposta que você mandou, sem tocar na internet. O teste roda offline, em milissegundos, e dá o mesmo resultado toda vez. Você virou dono do comportamento da API.
Como usar na prática
O fake() é flexível. Alguns cenários que você vai usar toda hora:
// Fingir QUALQUER requisição como 200 vazio (o mais simples)
Http::fake();
// Respostas diferentes por URL
Http::fake([
'github.com/*' => Http::response(['plano' => 'pro'], 200),
'viacep.com.br/*' => Http::response('', 404), // simula CEP não achado
]);
// Simular a API fora do ar (erro 500) — o caminho que ninguém testa
Http::fake([
'gateway.com/*' => Http::response('Erro interno', 500),
]);
Repara no último: agora você consegue testar o caminho de falha. "Se o gateway devolver 500, meu app mostra uma mensagem amigável ou explode na cara do usuário?" Sem fake(), você nunca teve como responder isso.
Não basta simular: confirme que você mandou certo
Aqui mora a pegadinha que separa o teste que testa do teste que só finge.
Simular a resposta não garante que você montou a requisição direito. Passou o header de autenticação? Mandou o valor no campo certo? O Http::assertSent() confere isso:
Http::fake();
$this->service->cobrar(valor: 150, cartao: 'tok_abc');
Http::assertSent(function (Request $request) {
return $request->url() === 'https://gateway.com/charges'
&& $request->hasHeader('Authorization')
&& $request['amount'] === 150;
});
Agora o teste garante os dois lados: você mandou o que devia e reagiu certo à resposta.
Bônus: proíba requisições reais escaparem
Tem um detalhe traiçoeiro. Se você esquecer de fakear uma URL, a requisição sai de verdade — e você nem percebe que aquele teste ainda depende da internet.
O preventStrayRequests() fecha essa porta:
Http::preventStrayRequests();
Http::fake([
'gateway.com/*' => Http::response('ok'),
]);
Http::get('https://gateway.com/charges'); // ok, tá fakeado
Http::get('https://outra-api.com'); // 💥 lança exceção na hora
Qualquer requisição sem fake correspondente estoura na hora, em vez de vazar silenciosamente pra rede. Coloca isso no setUp() da sua suíte de testes e durma tranquilo.
Antes de você fechar a aba
A regra de ouro: teste não conversa com o mundo lá fora. Ele verifica o seu código, de forma rápida e previsível. A conversa real com a API você deixa pra um teste de integração separado, que roda de vez em quando — não a cada commit.
Um detalhe importante: isso só funciona se você usa o HTTP Client do Laravel (Http::). Se ainda chama Guzzle ou cURL na mão, o fake() não te alcança — e migrar pro Http:: é justamente o próximo passo (spoiler: ele também te dá timeout e retry de graça, mas isso é papo pra outro post).
Me conta: você mocka suas APIs nos testes ou ainda reza pro sandbox ficar de pé? 👀
Top comments (0)