diff --git a/tests/test_custom_api.py b/tests/test_custom_api.py new file mode 100644 index 0000000000000..147db0bebaae8 --- /dev/null +++ b/tests/test_custom_api.py @@ -0,0 +1,150 @@ +""" +自定义API测试 +这是一个示例测试文件,展示如何在FastAPI项目中编写测试 +""" + +from typing import Optional + +import pytest +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + +# 创建一个简单的FastAPI应用用于测试 +app = FastAPI() + + +# 定义数据模型 +class Item(BaseModel): + name: str + price: float + is_offer: bool = False + + +class User(BaseModel): + username: str + email: str + + +# 定义API路由 +@app.get("/") +def read_root(): + return {"message": "Hello Custom API"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} + + +@app.post("/items/") +def create_item(item: Item): + return {"item": item, "status": "created"} + + +@app.get("/users/{user_id}") +def get_user(user_id: int): + return {"user_id": user_id, "username": f"user_{user_id}"} + + +# 创建测试客户端 +client = TestClient(app) + + +# 测试用例 +class TestCustomAPI: + """自定义API测试类""" + + def test_read_root(self): + """测试根路径""" + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"message": "Hello Custom API"} + + def test_read_item_with_params(self): + """测试带参数的商品查询""" + response = client.get("/items/5?q=somequery") + assert response.status_code == 200 + assert response.json() == {"item_id": 5, "q": "somequery"} + + def test_read_item_without_params(self): + """测试不带查询参数的商品查询""" + response = client.get("/items/10") + assert response.status_code == 200 + assert response.json() == {"item_id": 10, "q": None} + + def test_create_item(self): + """测试创建商品""" + item_data = {"name": "Test Item", "price": 99.99, "is_offer": True} + response = client.post("/items/", json=item_data) + assert response.status_code == 200 + response_data = response.json() + assert response_data["status"] == "created" + assert response_data["item"]["name"] == "Test Item" + assert response_data["item"]["price"] == 99.99 + assert response_data["item"]["is_offer"] is True + + def test_get_user(self): + """测试获取用户信息""" + response = client.get("/users/123") + assert response.status_code == 200 + assert response.json() == {"user_id": 123, "username": "user_123"} + + @pytest.mark.parametrize( + "item_id,expected_id", + [ + (1, 1), + (42, 42), + (999, 999), + ], + ) + def test_read_item_parametrized(self, item_id, expected_id): + """参数化测试:测试不同的商品ID""" + response = client.get(f"/items/{item_id}") + assert response.status_code == 200 + assert response.json()["item_id"] == expected_id + + def test_invalid_item_id(self): + """测试无效的商品ID""" + response = client.get("/items/not_a_number") + assert response.status_code == 422 # 验证错误 + + def test_create_item_invalid_data(self): + """测试创建商品时的无效数据""" + invalid_data = { + "name": "Test Item", + # 缺少必需的price字段 + "is_offer": True, + } + response = client.post("/items/", json=invalid_data) + assert response.status_code == 422 # 验证错误 + + +# 独立的测试函数(不在类中) +def test_app_startup(): + """测试应用启动""" + assert app.title == "FastAPI" + + +def test_openapi_schema(): + """测试OpenAPI schema生成""" + response = client.get("/openapi.json") + assert response.status_code == 200 + schema = response.json() + assert "openapi" in schema + assert "info" in schema + + +# Fixture示例 +@pytest.fixture +def sample_item(): + """测试用的示例商品数据""" + return {"name": "Sample Item", "price": 50.0, "is_offer": False} + + +def test_with_fixture(sample_item): + """使用fixture的测试""" + response = client.post("/items/", json=sample_item) + assert response.status_code == 200 + response_data = response.json() + assert response_data["item"]["name"] == sample_item["name"]