0
# Testing Support
1
2
FastAPI provides comprehensive testing capabilities through the TestClient class, which enables testing of FastAPI applications with full HTTP request simulation. The TestClient is built on top of HTTPX and provides a convenient interface for testing API endpoints without needing to run a live server.
3
4
## Capabilities
5
6
### TestClient Class
7
8
A test client for testing FastAPI applications with comprehensive HTTP request simulation capabilities.
9
10
```python { .api }
11
class TestClient:
12
def __init__(
13
self,
14
app: ASGIApp,
15
base_url: str = "http://testserver",
16
raise_server_exceptions: bool = True,
17
root_path: str = "",
18
backend: str = "asyncio",
19
backend_options: dict = None,
20
cookies: httpx.Cookies = None,
21
headers: dict = None,
22
follow_redirects: bool = False,
23
) -> None:
24
"""
25
Create a test client for a FastAPI application.
26
27
Parameters:
28
- app: The FastAPI application to test
29
- base_url: Base URL for requests (default: http://testserver)
30
- raise_server_exceptions: Whether to raise server exceptions during tests
31
- root_path: Root path for the application
32
- backend: Async backend to use (asyncio or trio)
33
- backend_options: Options for the async backend
34
- cookies: Default cookies for requests
35
- headers: Default headers for requests
36
- follow_redirects: Whether to automatically follow redirects
37
"""
38
```
39
40
### HTTP Methods
41
42
Standard HTTP methods for testing API endpoints with full request and response handling.
43
44
```python { .api }
45
def get(self, url: str, **kwargs) -> httpx.Response:
46
"""Send GET request to the specified URL."""
47
48
def post(self, url: str, **kwargs) -> httpx.Response:
49
"""Send POST request with optional data/json body."""
50
51
def put(self, url: str, **kwargs) -> httpx.Response:
52
"""Send PUT request with optional data/json body."""
53
54
def delete(self, url: str, **kwargs) -> httpx.Response:
55
"""Send DELETE request to the specified URL."""
56
57
def patch(self, url: str, **kwargs) -> httpx.Response:
58
"""Send PATCH request with optional data/json body."""
59
60
def head(self, url: str, **kwargs) -> httpx.Response:
61
"""Send HEAD request to the specified URL."""
62
63
def options(self, url: str, **kwargs) -> httpx.Response:
64
"""Send OPTIONS request to the specified URL."""
65
66
def request(
67
self,
68
method: str,
69
url: str,
70
**kwargs
71
) -> httpx.Response:
72
"""Send request with specified HTTP method."""
73
```
74
75
### Context Manager Support
76
77
TestClient supports context manager protocol for proper resource cleanup.
78
79
```python { .api }
80
def __enter__(self) -> TestClient:
81
"""Enter context manager."""
82
83
def __exit__(self, *args) -> None:
84
"""Exit context manager and cleanup resources."""
85
```
86
87
### WebSocket Testing
88
89
Support for testing WebSocket connections.
90
91
```python { .api }
92
def websocket_connect(
93
self,
94
url: str,
95
subprotocols: List[str] = None,
96
**kwargs
97
) -> WebSocketTestSession:
98
"""Create WebSocket connection for testing."""
99
```
100
101
## Usage Examples
102
103
### Basic API Testing
104
105
```python
106
from fastapi import FastAPI
107
from fastapi.testclient import TestClient
108
109
app = FastAPI()
110
111
@app.get("/items/{item_id}")
112
def read_item(item_id: int, q: str = None):
113
return {"item_id": item_id, "q": q}
114
115
@app.post("/items/")
116
def create_item(item: dict):
117
return item
118
119
# Create test client
120
client = TestClient(app)
121
122
def test_read_item():
123
response = client.get("/items/1?q=test")
124
assert response.status_code == 200
125
assert response.json() == {"item_id": 1, "q": "test"}
126
127
def test_create_item():
128
item_data = {"name": "Test Item", "price": 10.50}
129
response = client.post("/items/", json=item_data)
130
assert response.status_code == 200
131
assert response.json() == item_data
132
```
133
134
### Testing with Authentication
135
136
```python
137
from fastapi import FastAPI, Depends, HTTPException, status
138
from fastapi.security import HTTPBearer
139
from fastapi.testclient import TestClient
140
141
app = FastAPI()
142
security = HTTPBearer()
143
144
@app.get("/protected")
145
def protected_endpoint(token: str = Depends(security)):
146
if token.credentials != "valid-token":
147
raise HTTPException(status_code=401, detail="Invalid token")
148
return {"message": "Protected data"}
149
150
client = TestClient(app)
151
152
def test_protected_endpoint():
153
# Test without token
154
response = client.get("/protected")
155
assert response.status_code == 403
156
157
# Test with invalid token
158
response = client.get(
159
"/protected",
160
headers={"Authorization": "Bearer invalid-token"}
161
)
162
assert response.status_code == 401
163
164
# Test with valid token
165
response = client.get(
166
"/protected",
167
headers={"Authorization": "Bearer valid-token"}
168
)
169
assert response.status_code == 200
170
assert response.json() == {"message": "Protected data"}
171
```
172
173
### Testing File Uploads
174
175
```python
176
from fastapi import FastAPI, File, UploadFile
177
from fastapi.testclient import TestClient
178
import io
179
180
app = FastAPI()
181
182
@app.post("/upload/")
183
def upload_file(file: UploadFile = File(...)):
184
return {"filename": file.filename, "size": len(file.file.read())}
185
186
client = TestClient(app)
187
188
def test_file_upload():
189
test_file = io.BytesIO(b"test file content")
190
response = client.post(
191
"/upload/",
192
files={"file": ("test.txt", test_file, "text/plain")}
193
)
194
assert response.status_code == 200
195
data = response.json()
196
assert data["filename"] == "test.txt"
197
assert data["size"] > 0
198
```
199
200
### Testing with Context Manager
201
202
```python
203
from fastapi import FastAPI
204
from fastapi.testclient import TestClient
205
206
app = FastAPI()
207
208
@app.get("/")
209
def read_root():
210
return {"Hello": "World"}
211
212
def test_with_context_manager():
213
with TestClient(app) as client:
214
response = client.get("/")
215
assert response.status_code == 200
216
assert response.json() == {"Hello": "World"}
217
```
218
219
### WebSocket Testing
220
221
```python
222
from fastapi import FastAPI, WebSocket
223
from fastapi.testclient import TestClient
224
225
app = FastAPI()
226
227
@app.websocket("/ws")
228
async def websocket_endpoint(websocket: WebSocket):
229
await websocket.accept()
230
await websocket.send_text("Hello WebSocket!")
231
await websocket.close()
232
233
client = TestClient(app)
234
235
def test_websocket():
236
with client.websocket_connect("/ws") as websocket:
237
data = websocket.receive_text()
238
assert data == "Hello WebSocket!"
239
```
240
241
## Types
242
243
```python { .api }
244
from typing import Any, Dict, List, Optional, Union
245
import httpx
246
from starlette.types import ASGIApp
247
248
# Test client response type
249
TestResponse = httpx.Response
250
251
# WebSocket test session
252
class WebSocketTestSession:
253
def send_text(self, data: str) -> None: ...
254
def send_bytes(self, data: bytes) -> None: ...
255
def send_json(self, data: Any) -> None: ...
256
def receive_text(self) -> str: ...
257
def receive_bytes(self) -> bytes: ...
258
def receive_json(self) -> Any: ...
259
def close(self, code: int = 1000) -> None: ...
260
```