FastAPI Testing
FastAPI based on StarletteTestClientProvides convenient testing support, allowing you to test API requests and responses without starting a server.
Install dependencies
TestClientbased onhttpx, you need to install:
pip install httpx
Basic test
UsageTestClientCreate a test client, then use it likehttpxsend the request in the same way:
Example
from fastapi.testclient import TestClient
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
# Create a test client
client = TestClient(app)
# Test Function
def test_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
TestClientDirectly invokes the FastAPI application, bypassing the network layer, so tests run very fast. You don't need to start the Uvicorn server.
Test various request types
Example
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)
# Test POST request
def test_create_item():
response = client.post(
"/items/",
json={"name": "Foo", "price": 42.0}, # Send JSON request body
)
assert response.status_code == 200
assert response.json() == {"name": "Foo", "price": 42.0}
# Test GET request
def test_read_item():
response = client.get("/items/1")
assert response.status_code == 200
assert response.json() == {"item_id": 1}
# Test PUT request
def test_update_item():
response = client.put(
"/items/1",
json={"name": "Bar", "price": 50.0},
)
assert response.status_code == 200
# Test DELETE request
def test_delete_item():
response = client.delete("/items/1")
assert response.status_code == 200
assert response.json() == {"deleted": 1}
Test query parameters and request headers
Example
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)
# Test query parameters
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}
# Test request headers
def test_read_items_with_header():
response = client.get(
"/items/",
headers={"X-Token": "fake-token"}, # Send custom request headers
)
assert response.status_code == 200
assert response.json()["x_token"] == "fake-token"
Test exception responses
Example
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)
# Test normal response
def test_read_item():
response = client.get("/items/1")
assert response.status_code == 200
# Test error response
def test_read_item_not_found():
response = client.get("/items/0")
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
# Test validation error
def test_read_item_invalid_id():
response = client.get("/items/foo")
assert response.status_code == 422 # Validation Failed
Run tests using pytest
Save the test code astest_main.py, then run:
$ pytest test_main.py # 显示详细输出 $ pytest test_main.py -v # 显示 print 输出 $ pytest test_main.py -s
pytest will automatically discover files and functionstest_whose names start with the "test_" prefix.
Override dependencies in tests
In tests, you may need to override certain dependencies (such as database connections, authentication logic):
Example
from fastapi.testclient import TestClient
app = FastAPI()
# Actual dependency function
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():
# Override Dependencies
app.dependency_overrides[get_query_param] = lambda: "test_value"
response = client.get("/items/")
assert response.json() == {"query": "test_value"}
# Clear Overrides
app.dependency_overrides.clear()
app.dependency_overridesAllows you to replace any dependency function during testing, making it ideal for simulating scenarios like database connections and external API calls. Remember to clear the overrides after testing.
Summary
- Usage
TestClientDirectly test the FastAPI application without starting a server. - Supports testing of all HTTP methods, including GET, POST, PUT, DELETE, etc.
- Can test query parameters, request headers, request bodies, exception responses, etc.
- Usage
app.dependency_overridesOverride dependencies in tests - With pytest, you can easily organize and run tests.