RESPX intercepta requisições do HTTPX e devolve respostas controladas. Assim, um teste valida sucesso, erro e timeout sem depender de rede, credenciais ou disponibilidade externa.
Simular uma rota
python -m pip install pytest httpx respx
import httpx
def obter_status(client: httpx.Client) -> str:
response = client.get("https://api.example.com/status")
response.raise_for_status()
return response.json()["status"]
def test_obter_status(respx_mock) -> None:
rota = respx_mock.get("https://api.example.com/status").respond(
200, json={"status": "ok"}
)
with httpx.Client() as client:
assert obter_status(client) == "ok"
assert rota.called
Registre apenas as rotas esperadas. Uma URL ou método inesperado deve falhar, pois pode indicar regressão no contrato. Valide também corpo, query e headers relevantes, sem acoplar o teste a detalhes sem importância.
O guia de HTTPX em Python cobre clientes e timeouts. Para corrotinas, combine RESPX com pytest-asyncio.
Falhas e limites
Definir o escopo do router
A fixture respx_mock remove rotas após cada caso. @respx.mock oferece isolamento como decorator; with respx.mock: restringe a interceptação a um bloco. Mantenha a ativação estreita. Rotas devem explicar cada requisição externa. Uma chamada sem correspondência costuma indicar mudança de método, host, caminho ou query. Evite respostas catch-all que escondem regressões.
Verificar o contrato relevante
Rotas podem restringir método, URL, query, headers e conteúdo. Verifique apenas detalhes prometidos pelo cliente. Paginação pertence ao contrato; ordem incidental de chaves JSON não.
def test_envia_pagina_e_token(respx_mock) -> None:
rota = respx_mock.get(
"https://api.example.com/items",
params={"page": "2"},
headers={"authorization": "Bearer token-de-teste"},
).respond(200, json={"items": []})
with httpx.Client() as client:
resposta = client.get(
"https://api.example.com/items",
params={"page": 2},
headers={"authorization": "Bearer token-de-teste"},
)
assert resposta.json() == {"items": []}
assert rota.call_count == 1
Nunca use token de produção numa fixture. Um valor claramente fictício prova a composição do header sem introduzir segredo.
Inspecionar a requisição capturada
O histórico expõe o httpx.Request, útil quando colocar todo o payload no matcher prejudicaria a falha.
request = rota.calls.last.request
assert request.method == "GET"
assert request.url.params["page"] == "2"
Em JSON, compare a estrutura decodificada, não espaços ou ordem. Verifique credenciais apenas por presença ou valor sintético e não imprima autorização numa assertion personalizada. Com várias chamadas, confira contagem e sequência relevante.
Cobrir AsyncClient
RESPX intercepta httpx.AsyncClient no mesmo router. Combine-o com pytest-asyncio e aguarde o código normalmente.
@pytest.mark.asyncio
async def test_status_async(respx_mock) -> None:
rota = respx_mock.get("https://api.example.com/status").respond(
200, json={"status": "ok"}
)
async with httpx.AsyncClient() as client:
assert await buscar_status(client) == "ok"
assert rota.called
Injete clientes na aplicação. Construção oculta dificulta controlar timeout, transporte, base URL e ciclo de vida. Uma fixture compartilhada precisa fechar o cliente depois de yield.
Distinguir HTTP e transporte
Um 503 é resposta HTTP válida e chega a raise_for_status(). ConnectTimeout, ReadTimeout e ConnectError ocorrem antes de uma resposta utilizável. Use side_effect:
respx_mock.get("https://api.example.com/status").mock(
side_effect=httpx.ConnectTimeout("connection timed out")
)
Verifique o erro estável da aplicação, não toda a mensagem da dependência. Confirme que 4xx não elegível não recebe retry e que falhas elegíveis respeitam o limite. Injete sleep ou backoff para o teste não esperar segundos reais.
Testar sequências de retry
Um teste deve mostrar falha intermediária e resultado final. A rota pode devolver respostas sucessivas ou usar callback contador. Verifique valor final e número exato de tentativas. Inclua o esgotamento para revelar erros de contagem.
A política pertence à produção; RESPX só oferece observações. A aplicação decide erros, espera e segurança da repetição. Repetir POST pode duplicar ação sem chave de idempotência.
Usar callbacks com moderação
Um callback lê a requisição e devolve httpx.Response, útil para paginação ou resposta dependente da entrada. Mantenha-o muito mais simples que o serviço. Recriar validação, autenticação e armazenamento produz uma segunda implementação sujeita ao mesmo equívoco.
Prefira respostas estáticas. Pequenas fábricas ajudam quando testes compartilham payload documentado e alteram campos relevantes. Grandes respostas de produção escondem o comportamento testado.
Separar camadas de teste
RESPX verifica a reação ao contrato da fixture; não prova que o provedor ainda o implementa. Mantenha poucos testes de contrato ou sandbox em ambiente controlado. Separe-os da suíte offline e proteja credenciais.
Registre fonte e data de fixtures representativas. Atualize-as após consultar documentação oficial ou captura sanitizada, não apenas para deixar o teste verde. End-to-end deve ser reduzido porque depende de disponibilidade externa.
Bloquear rede acidental
Revisar a qualidade das fixtures
Resposta simulada é dado de teste e merece revisão. Use o menor payload que preserve o comportamento, mas mantenha campos obrigatórios e tipos realistas. Nomeie fábricas pelo conceito do provedor, não pelo nome de um teste. Uma descrição OpenAPI pode orientar o formato, porém o cenário ainda exige revisão humana.
Quando um incidente revelar resposta não prevista, adicione primeiro uma fixture sanitizada e uma assertion que reproduza a falha, depois corrija o adapter. Não copie dados pessoais, tokens, identificadores de trace nem corpos proprietários para o repositório. Registre por que aquele formato é representativo.
Organizar manutenção e diagnóstico
Deixe base URL e construção do cliente num único adapter, facilitando atualizar versão, autenticação e timeouts. Fixtures podem ficar próximas dos testes quando são específicas; fábricas compartilhadas pertencem a um módulo pequeno, sem transformar todos os casos numa abstração difícil de ler.
Uma falha deve mostrar rota esperada, chamada recebida e diferença relevante, sem segredos. Confirme que assertions do router executam mesmo quando outra assertion falha. Uma rota esperada e não usada pode indicar curto-circuito correto, então torne essa expectativa explícita.
Antes do merge, rode o teste sem acesso à rede, confira sucesso, status inválido e erro de transporte, e execute a suíte completa. Revise também compatibilidade entre versões fixadas de HTTPX e RESPX. Se a atualização mudar transporte ou matching, adapte um caso de cada padrão antes de aplicar mudança mecânica em todas as fixtures.
Também cubra paginação quando o cliente a implementa. A primeira resposta deve fornecer o cursor e a segunda validar que ele foi enviado corretamente. Limite o número de páginas para testar proteção contra cursor repetido. Em downloads, valide streaming, fechamento e tratamento de resposta truncada sem manter arquivos grandes no repositório.
Para uploads, compare nome, media type e bytes essenciais, evitando depender do boundary aleatório do multipart. Se a aplicação assina requisições, injete relógio e credencial fictícia para produzir assinatura determinística. Esses testes pertencem ao adapter, pois expressam o protocolo externo.
Ative router estrito e registre endpoints esperados. Centralize clientes com base URL, timeouts e injeção. Um hostname inesperado fica visível imediatamente.
Cubra redirects, JSON inválido, corpo vazio, rate limit, autenticação e resposta parcial conforme o contrato do adapter. Não teste cada recurso do HTTPX; foque decisões próprias. Verifique chamadas quando a presença ou ausência da requisição for um resultado.
Use side_effect para simular httpx.ConnectTimeout ou uma sequência de respostas. Isso permite verificar retry e mensagens de erro de forma determinística. Não replique toda a API remota no mock: mantenha exemplos mínimos e acrescente testes de contrato separados para detectar mudanças reais.
A documentação oficial do RESPX, consultada em 22 de julho de 2026, apresenta fixture, padrões de rota, respostas e histórico de chamadas. Fixe versões compatíveis de RESPX e HTTPX para evitar mudanças inesperadas na integração.