Pruebas de FastAPI
FastAPI, basado en Starlette,TestClientproporciona un soporte de pruebas conveniente que permite probar las solicitudes y respuestas de la API sin iniciar el servidor.
Instalar dependencias
TestClientBasado enhttpx, es necesario instalar:
pip install httpx
Pruebas básicas
UsaTestClientpara crear un cliente de prueba y luego, igual que conhttpx, envía solicitudes:
Ejemplo
from fastapi.testclient import TestClient
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
# Crear el cliente de prueba
client = TestClient(app)
# Función de prueba
def test_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
TestClientLlama directamente a la aplicación FastAPI sin pasar por la capa de red, por lo que las pruebas son muy rápidas. No necesitas iniciar el servidor Uvicorn.
Probar varios tipos de solicitudes
Ejemplo
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
return {"name": item.name, "price": item.price}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, "name": item.name}
@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
return {"deleted": item_id}
client = TestClient(app)
# Probar solicitud POST
def test_create_item():
response = client.post(
"/items/",
json={"name": "Foo", "price": 42.0}, # Enviar cuerpo de solicitud JSON
)
assert response.status_code == 200
assert response.json() == {"name": "Foo", "price": 42.0}
# Probar solicitud GET
def test_read_item():
response = client.get("/items/1")
assert response.status_code == 200
assert response.json() == {"item_id": 1}
# Probar solicitud PUT
def test_update_item():
response = client.put(
"/items/1",
json={"name": "Bar", "price": 50.0},
)
assert response.status_code == 200
# Probar solicitud DELETE
def test_delete_item():
response = client.delete("/items/1")
assert response.status_code == 200
assert response.json() == {"deleted": 1}
Probar parámetros de consulta y encabezados de solicitud
Ejemplo
from fastapi import FastAPI, Header
from fastapi.testclient import TestClient
app = FastAPI()
@app.get("/items/")
async def read_items(
skip: int = 0,
limit: int = 10,
x_token: Annotated[str | None, Header()] = None,
):
return {"skip": skip, "limit": limit, "x_token": x_token}
client = TestClient(app)
# Probar parámetros de consulta
def test_read_items_with_params():
response = client.get("/items/?skip=5&limit=20")
assert response.status_code == 200
assert response.json() == {"skip": 5, "limit": 20, "x_token": None}
# Probar encabezados de solicitud
def test_read_items_with_header():
response = client.get(
"/items/",
headers={"X-Token": "fake-token"}, # Enviar encabezados de solicitud personalizados
)
assert response.status_code == 200
assert response.json()["x_token"] == "fake-token"
Probar respuestas de error
Ejemplo
from fastapi.testclient import TestClient
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 0:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}
client = TestClient(app)
# Probar respuesta normal
def test_read_item():
response = client.get("/items/1")
assert response.status_code == 200
# Probar respuesta de error
def test_read_item_not_found():
response = client.get("/items/0")
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
# Probar errores de validación
def test_read_item_invalid_id():
response = client.get("/items/foo")
assert response.status_code == 422 # Validación fallida
Ejecutar pruebas con pytest
Guarda el código de prueba comotest_main.py, y luego ejecuta:
$ pytest test_main.py # 显示详细输出 $ pytest test_main.py -v # 显示 print 输出 $ pytest test_main.py -s
pytest descubre automáticamentetest_los archivos y funciones que comienzan con el prefijo.
Sobrescribir dependencias en las pruebas
En las pruebas, es posible que necesites sobrescribir ciertas dependencias (como la conexión a la base de datos o la lógica de autenticación):
Ejemplo
from fastapi.testclient import TestClient
app = FastAPI()
# Función de dependencia real
def get_query_param():
return "real_value"
@app.get("/items/")
async def read_items(query: str = Depends(get_query_param)):
return {"query": query}
client = TestClient(app)
def test_with_override():
# Sobrescribir la dependencia
app.dependency_overrides[get_query_param] = lambda: "test_value"
response = client.get("/items/")
assert response.json() == {"query": "test_value"}
# Eliminar la sobrescritura
app.dependency_overrides.clear()
app.dependency_overridesTe permite reemplazar cualquier función de dependencia en las pruebas, ideal para simular escenarios como conexiones de base de datos o llamadas a API externas. Recuerda eliminar la sobrescritura al finalizar las pruebas.
Resumen
- Usar
TestClientpara probar directamente la aplicación FastAPI sin iniciar el servidor - Admite pruebas de todos los métodos HTTP, como GET, POST, PUT, DELETE, etc.
- Puede probar parámetros de consulta, encabezados de solicitud, cuerpo de solicitud, respuestas de error, etc.
- Usar
app.dependency_overridespara sobrescribir dependencias en las pruebas - Junto con pytest, se pueden organizar y ejecutar pruebas fácilmente.