RESPX intercepta peticiones de HTTPX y devuelve respuestas controladas. Así una prueba cubre éxito, errores y timeout sin depender de red, credenciales o disponibilidad externa.
Simular una ruta
Definir el alcance del router
La fixture respx_mock elimina rutas después de cada caso. @respx.mock ofrece aislamiento como decorador y with respx.mock: limita la interceptación a un bloque. Mantén la activación estrecha para que el setup no dependa del mock accidentalmente.
Las rutas registradas deben explicar cada petición saliente. Una llamada sin coincidencia suele indicar un cambio de método, host, path o query. Evita una respuesta catch-all que convierta esas regresiones en falsos positivos. Si una llamada no registrada es intencional, documenta el motivo e impide que llegue a internet.
Comprobar el contrato relevante
Los patrones pueden restringir método, URL, query, headers y contenido. Comprueba solo detalles prometidos por el cliente. La página solicitada pertenece al contrato; el orden incidental de claves JSON no.
def test_envia_pagina_y_token(respx_mock) -> None:
ruta = respx_mock.get(
"https://api.example.com/items",
params={"page": "2"},
headers={"authorization": "Bearer token-de-prueba"},
).respond(200, json={"items": []})
with httpx.Client() as client:
respuesta = client.get(
"https://api.example.com/items",
params={"page": 2},
headers={"authorization": "Bearer token-de-prueba"},
)
assert respuesta.json() == {"items": []}
assert ruta.call_count == 1
Nunca uses un token de producción en una fixture. Un valor claramente ficticio demuestra la composición del header sin introducir secretos.
Inspeccionar la petición capturada
El historial expone el httpx.Request, útil si poner todo el payload en el matcher empeora el mensaje de error.
request = ruta.calls.last.request
assert request.method == "GET"
assert request.url.params["page"] == "2"
Para JSON, compara la estructura decodificada, no espacios u orden. Comprueba credenciales solo por presencia o valor sintético y no imprimas autorización en assertions personalizadas. Con varias llamadas, verifica el conteo y la secuencia relevante.
Cubrir AsyncClient
RESPX intercepta httpx.AsyncClient en el mismo router. Combínalo con pytest-asyncio.
@pytest.mark.asyncio
async def test_estado_async(respx_mock) -> None:
ruta = respx_mock.get("https://api.example.com/status").respond(
200, json={"status": "ok"}
)
async with httpx.AsyncClient() as client:
assert await buscar_estado(client) == "ok"
assert ruta.called
Inyecta clientes en la aplicación. Crearlos de forma oculta dificulta controlar timeout, transporte, base URL y ciclo de vida. Una fixture compartida debe cerrar el cliente después de yield.
Distinguir HTTP y transporte
Un 503 es una respuesta HTTP válida que llega a raise_for_status(). ConnectTimeout, ReadTimeout y ConnectError ocurren antes de obtener una respuesta útil. Usa side_effect:
respx_mock.get("https://api.example.com/status").mock(
side_effect=httpx.ConnectTimeout("connection timed out")
)
Comprueba el error estable de la aplicación, no todo el texto de la dependencia. Verifica que un 4xx no elegible no se reintenta y que fallos elegibles respetan el límite. Inyecta sleep o backoff para no esperar segundos reales.
Probar secuencias de retry
La prueba debe mostrar fallo intermedio y resultado final. Una ruta puede devolver respuestas sucesivas o usar un callback contador. Comprueba valor y número exacto de intentos. Incluye el agotamiento para revelar errores de conteo.
La política pertenece a producción; RESPX solo aporta observaciones. La aplicación decide errores, espera y seguridad. Repetir POST puede duplicar una acción sin clave de idempotencia.
Usar callbacks con moderación
Un callback lee la petición y devuelve httpx.Response, útil para paginación o respuestas dependientes de entrada. Debe ser mucho más simple que el servicio. Reproducir validación, autenticación y almacenamiento crea una segunda implementación que puede compartir el mismo error.
Prefiere respuestas estáticas. Pequeñas fábricas ayudan cuando varias pruebas comparten un payload documentado y cambian campos relevantes. Respuestas enormes de producción esconden lo que se prueba.
Separar capas de prueba
RESPX verifica la reacción al contrato de una fixture; no demuestra que el proveedor aún lo implemente. Conserva pocas pruebas de contrato o sandbox en entorno controlado. Sepáralas de la suite offline y protege credenciales.
Registra fuente y fecha de fixtures representativas. Actualízalas tras revisar documentación oficial o capturas saneadas, no solo para dejar verde el caso. Las pruebas end-to-end deben ser pocas por su dependencia externa.
Impedir red accidental
Revisar la calidad de las fixtures
Una respuesta simulada es dato de prueba y merece revisión. Usa el payload más pequeño que conserve el comportamiento, con campos obligatorios y tipos realistas. Nombra las fábricas por el concepto del proveedor, no por un caso concreto. Una descripción OpenAPI puede orientar el formato, pero el escenario requiere revisión humana.
Si un incidente revela una respuesta no prevista, añade primero una fixture saneada y una assertion que reproduzca el fallo, luego corrige el adaptador. No copies datos personales, tokens, identificadores de trace ni cuerpos propietarios al repositorio. Registra por qué la forma es representativa.
Organizar mantenimiento y diagnóstico
Centraliza base URL y construcción del cliente en un adaptador para actualizar autenticación, versión y timeouts. Las fixtures específicas pueden vivir junto a los tests; las fábricas compartidas deben permanecer pequeñas y legibles.
El fallo debe mostrar ruta esperada, llamada recibida y diferencia relevante, sin secretos. Asegura que las comprobaciones del router se ejecutan aunque otra assertion falle. Una ruta esperada no utilizada puede representar un cortocircuito correcto, así que declara esa expectativa.
Antes de integrar, ejecuta sin red, cubre éxito, status inválido y error de transporte, y después corre toda la suite. Revisa compatibilidad entre versiones fijadas de HTTPX y RESPX. Si una actualización cambia transporte o matching, adapta un ejemplo de cada patrón antes de una modificación mecánica global.
Cubre paginación cuando el cliente la implemente. Haz que la primera respuesta entregue un cursor y comprueba que la segunda petición lo envíe. Añade un máximo de páginas para un cursor repetido. En descargas, verifica streaming, cierre y respuesta truncada sin guardar archivos binarios grandes.
Para multipart compara nombre, media type y bytes relevantes, no el boundary aleatorio. Si la aplicación firma peticiones, inyecta reloj y credencial ficticia para producir una firma determinista. Estos casos pertenecen al adaptador porque describen el protocolo externo.
Activa un router estricto y registra endpoints esperados. Centraliza clientes con base URL, timeouts e inyección. Un hostname inesperado queda visible inmediatamente.
Cubre redirects, JSON inválido, cuerpo vacío, rate limit, autenticación y respuesta parcial según el contrato del adaptador. No pruebes cada función de HTTPX; céntrate en decisiones propias. Verifica llamadas cuando su presencia o ausencia sea un resultado.
python -m pip install pytest httpx respx
import httpx
def obtener_estado(client: httpx.Client) -> str:
response = client.get("https://api.example.com/status")
response.raise_for_status()
return response.json()["status"]
def test_obtener_estado(respx_mock) -> None:
ruta = respx_mock.get("https://api.example.com/status").respond(
200, json={"status": "ok"}
)
with httpx.Client() as client:
assert obtener_estado(client) == "ok"
assert ruta.called
Registra solo las rutas esperadas. Una URL o método inesperado debe fallar porque puede revelar una regresión. Comprueba cuerpo, query y headers relevantes sin acoplarte a detalles innecesarios.
La guía de HTTPX en Python cubre clientes y timeouts. Para corutinas, combina RESPX con pytest-asyncio.
Fallos y límites
Usa side_effect para httpx.ConnectTimeout o secuencias de respuestas. Esto hace deterministas los reintentos y errores. No reproduzcas toda la API remota: mantén mocks pequeños y añade pruebas de contrato separadas.
La documentación oficial de RESPX, consultada el 22 de julio de 2026, explica fixtures, patrones de ruta, respuestas e historial de llamadas. Fija versiones compatibles de RESPX y HTTPX.