💻 Exemplos: Capítulo 16: Testes Automatizados com Pytest, HTTPX AsyncClient e Fixtures
Especialização em Backend com Python & FastAPI • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 01 — Teste Síncrono de Endpoint com TestClient
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health() -> dict:
return {"status": "ok"}
@app.get("/itens/{item_id}")
def obter_item(item_id: int) -> dict:
if item_id <= 0:
return {"erro": "id inválido"}
return {"id": item_id, "nome": f"Item {item_id}"}
# test_main.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_health_ok():
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
def test_obter_item_existente():
response = client.get("/itens/10")
assert response.status_code == 200
assert response.json()["nome"] == "Item 10"
💻 Código de Exemplo 02 — Teste Assíncrono com httpx.AsyncClient e ASGITransport
# main_async.py
import asyncio
from fastapi import FastAPI
app = FastAPI()
@app.get("/processar")
async def processar_dados() -> dict:
await asyncio.sleep(0.01) # simula I/O assíncrono real (DB, HTTP externo)
return {"itens": [1, 2, 3], "total": 3}
# test_main_async.py
import pytest
from httpx import AsyncClient, ASGITransport
from main_async import app
@pytest.mark.asyncio
async def test_processar_dados_assincrono():
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as client:
response = await client.get("/processar")
assert response.status_code == 200
corpo = response.json()
assert corpo["total"] == 3
assert len(corpo["itens"]) == 3
💻 Código de Exemplo 03 — dependency_overrides com Banco SQLite em Memória
# app_pedidos.py
from fastapi import FastAPI, Depends
from sqlmodel import SQLModel, Field, Session, create_engine, select
class Pedido(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
cliente: str
total: float
engine = create_engine("sqlite:///producao.db") # banco real, nunca usado nos testes
def get_db():
with Session(engine) as session:
yield session
app = FastAPI()
@app.post("/pedidos", status_code=201)
def criar_pedido(cliente: str, total: float, db: Session = Depends(get_db)) -> Pedido:
pedido = Pedido(cliente=cliente, total=total)
db.add(pedido)
db.commit()
db.refresh(pedido)
return pedido
@app.get("/pedidos")
def listar_pedidos(db: Session = Depends(get_db)) -> list[Pedido]:
return db.exec(select(Pedido)).all()
# test_pedidos.py
import pytest
from fastapi.testclient import TestClient
from sqlmodel import SQLModel, create_engine, Session
from app_pedidos import app, get_db
engine_teste = create_engine("sqlite://", connect_args={"check_same_thread": False})
@pytest.fixture
def client():
SQLModel.metadata.create_all(engine_teste)
def get_db_teste():
with Session(engine_teste) as session:
yield session
app.dependency_overrides[get_db] = get_db_teste
with TestClient(app) as c:
yield c
app.dependency_overrides.clear()
SQLModel.metadata.drop_all(engine_teste)
def test_criar_e_listar_pedido(client):
resposta_criacao = client.post("/pedidos", params={"cliente": "Alice", "total": 250.0})
assert resposta_criacao.status_code == 201
resposta_listagem = client.get("/pedidos")
assert resposta_listagem.status_code == 200
assert len(resposta_listagem.json()) == 1
assert resposta_listagem.json()[0]["cliente"] == "Alice"