测试
Batman 希望在每次运行测试时无需启动完整服务器。Robyn 为他提供了内置的 TestClient —— 一个轻量的进程内测试客户端,它直接执行路由处理器,使测试运行快速且具有确定性。
快速上手
TestClient 包装了一个 Robyn 应用,允许你像发起真实 HTTP 请求一样调用路由——但这一切都在进程内完成。无需端口、无需套接字、无需启动服务器。
从 robyn.testing 导入 TestClient,将你的应用传入它,然后开始发起请求:
Request
from robyn import Robyn
from robyn.testing import TestClient
app = Robyn(__file__)
@app.get("/hello")
def hello(request):
return "Hello, World!"
client = TestClient(app)
def test_hello():
response = client.get("/hello")
assert response.status_code == 200
assert response.text == "Hello, World!"
TestResponse 对象
每个请求方法都会返回一个 TestResponse,包含以下属性:
| Property | Type | Description |
|---|---|---|
status_code | int | HTTP 状态码 |
text | str | 解码后的响应主体字符串 |
content | bytes | 原始响应主体(字节) |
headers | Headers | 响应头 |
ok | bool | 如果状态为 2xx 则为 True |
TestResponse 还提供 .json() 方法用于将响应体解析为 JSON。
Request
@app.get("/users")
def get_users(request):
return [{"name": "Batman"}, {"name": "Robin"}]
def test_json_response():
response = client.get("/users")
assert response.ok
data = response.json()
assert len(data) == 2
assert data[0]["name"] == "Batman"
HTTP 方法
TestClient 支持所有常见的 HTTP 方法。通常会发送请求体的方法(如 POST、PUT、PATCH、DELETE)提供了 json_data 参数以便快捷发送 JSON。
使用 json_data 发送 JSON 负载——客户端会自动设置 Content-Type: application/json 并序列化数据:
Request
@app.post("/items")
def create_item(request):
body = request.json()
return {"id": 1, "name": body["name"]}
def test_post_json():
response = client.post("/items", json_data={"name": "Batarang"})
assert response.status_code == 200
assert response.json()["name"] == "Batarang"
你也可以发送原始字符串或字节体、自定义头、查询参数、表单数据和文件:
Request
def test_with_all_options():
response = client.post(
"/search",
body="raw body content",
headers={"X-Custom": "value"},
query_params={"q": "batman"},
)
assert response.ok
路径参数
带路径参数的路由在测试环境中与生产环境行为一致。TestClient 会匹配路由模式并自动提取参数。
路径参数会从 URL 中解析,并通过 Robyn 的参数解析管道传入处理函数:
Request
@app.get("/users/:user_id")
def get_user(request, user_id: int):
return {"user_id": user_id}
def test_path_params():
response = client.get("/users/42")
assert response.json()["user_id"] == 42
测试中间件
TestClient 会在相同顺序中复现完整的请求管道——包括前置中间件、处理器、全局响应头和后置中间件,行为与 Rust 运行时一致。
会修改请求或响应的中间件在测试中会如同生产环境一样执行:
Request
@app.before_request()
def add_request_id(request):
request.headers.set("X-Request-ID", "test-123")
return request
@app.after_request()
def add_server_header(response):
response.headers.set("X-Server", "Robyn")
return response
@app.get("/protected")
def protected(request):
return request.headers.get("X-Request-ID")
def test_middleware_pipeline():
response = client.get("/protected")
assert response.text == "test-123"
assert response.headers.get("X-Server") == "Robyn"
作为上下文管理器使用
TestClient 实现了上下文管理协议。与 with 一起使用时,内部事件循环会自动清理:
Request
def test_with_context_manager():
with TestClient(app) as client:
response = client.get("/hello")
assert response.ok
# 事件循环在此处关闭
使用 pytest 运行测试
由于 TestClient 不会启动服务器,测试运行速度与普通单元测试相同。直接使用 pytest 即可——不需要特殊插件或 fixture。
一个典型的测试文件:
Test File
import pytest
from robyn import Robyn
from robyn.testing import TestClient
app = Robyn(__file__)
@app.get("/")
def index(request):
return "Home"
@app.get("/health")
def health(request):
return {"status": "ok"}
@app.post("/echo")
def echo(request):
return request.json()
client = TestClient(app)
def test_index():
assert client.get("/").text == "Home"
def test_health():
data = client.get("/health").json()
assert data["status"] == "ok"
def test_echo():
payload = {"message": "hello"}
response = client.post("/echo", json_data=payload)
assert response.json() == payload
def test_not_found():
response = client.get("/nonexistent")
assert response.status_code == 404
Run with:
pytest test_app.py -v
可用方法
| Method | Signature |
|---|---|
client.get(path, **kw) | GET 请求 |
client.post(path, json_data=None, **kw) | POST 请求 |
client.put(path, json_data=None, **kw) | PUT 请求 |
client.patch(path, json_data=None, **kw) | PATCH 请求 |
client.delete(path, json_data=None, **kw) | DELETE 请求 |
client.head(path, **kw) | HEAD 请求 |
client.options(path, **kw) | OPTIONS 请求 |
所有方法接受以下关键字参数:
| Argument | Type | Description |
|---|---|---|
body | `str \ | bytes` |
headers | dict | 请求头 |
query_params | dict | 查询字符串参数 |
form_data | dict | 表单数据字段 |
files | dict | 文件上传(名称 → bytes) |
