plan_execute/tests/test_basic.py

176 lines
6.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""基础测试模块。
测试业务逻辑层 (TodoService) 和 API 层 (FastAPI 路由) 的核心功能。
"""
import pytest
from httpx import AsyncClient, ASGITransport
from app.main import app
from app.services import TodoService
from app.models import TodoCreate, TodoUpdate
# ============================================================
# 单元测试 — TodoService 业务逻辑
# ============================================================
class TestTodoService:
"""TodoService 的单元测试。"""
@pytest.fixture
def service(self):
"""每个测试使用全新的 TodoService 实例。"""
return TodoService()
def test_create_todo(self, service):
"""测试创建任务:应返回带 ID 和默认字段的有效任务。"""
data = TodoCreate(title="测试任务", description="测试描述")
item = service.create_todo(data)
assert item.id == 1
assert item.title == "测试任务"
assert item.description == "测试描述"
assert item.completed is False
def test_list_todos_empty(self, service):
"""测试空列表:新建服务应返回空列表。"""
items, total = service.list_todos()
assert items == []
assert total == 0
def test_list_todos_with_data(self, service):
"""测试列表:创建多个任务后应能正确返回。"""
service.create_todo(TodoCreate(title="任务1"))
service.create_todo(TodoCreate(title="任务2"))
items, total = service.list_todos()
assert total == 2
assert len(items) == 2
def test_get_todo_by_id(self, service):
"""测试根据 ID 获取任务。"""
created = service.create_todo(TodoCreate(title="查找测试"))
fetched = service.get_todo(created.id)
assert fetched is not None
assert fetched.title == "查找测试"
def test_get_todo_not_found(self, service):
"""测试获取不存在的任务应返回 None。"""
assert service.get_todo(999) is None
def test_update_todo(self, service):
"""测试更新任务:应正确修改标题和完成状态。"""
created = service.create_todo(TodoCreate(title="原标题"))
updated = service.update_todo(
created.id,
TodoUpdate(title="新标题", completed=True),
)
assert updated is not None
assert updated.title == "新标题"
assert updated.completed is True
def test_update_todo_not_found(self, service):
"""测试更新不存在的任务应返回 None。"""
result = service.update_todo(999, TodoUpdate(title=""))
assert result is None
def test_delete_todo(self, service):
"""测试删除任务:删除后应无法再获取。"""
created = service.create_todo(TodoCreate(title="待删除"))
deleted = service.delete_todo(created.id)
assert deleted is True
assert service.get_todo(created.id) is None
def test_delete_todo_not_found(self, service):
"""测试删除不存在的任务应返回 False。"""
result = service.delete_todo(999)
assert result is False
# ============================================================
# 集成测试 — FastAPI 路由
# ============================================================
@pytest.fixture
def client():
"""创建测试用的 AsyncClient绑定到 FastAPI 应用。"""
transport = ASGITransport(app=app)
return AsyncClient(transport=transport, base_url="http://test")
@pytest.mark.asyncio
async def test_api_root(client):
"""测试根路径返回 API 信息。"""
response = await client.get("/")
assert response.status_code == 200
data = response.json()
assert "name" in data
assert "version" in data
@pytest.mark.asyncio
async def test_api_create_todo(client):
"""测试 POST /api/todos 创建任务。"""
response = await client.post("/api/todos", json={
"title": "API 测试任务",
"description": "通过 API 创建",
})
assert response.status_code == 201
data = response.json()
assert data["code"] == 201
assert data["data"]["title"] == "API 测试任务"
@pytest.mark.asyncio
async def test_api_list_todos(client):
"""测试 GET /api/todos 获取任务列表。"""
# 先创建一条数据
await client.post("/api/todos", json={"title": "列表测试"})
response = await client.get("/api/todos")
assert response.status_code == 200
data = response.json()
assert data["code"] == 200
assert data["total"] >= 1
@pytest.mark.asyncio
async def test_api_get_todo(client):
"""测试 GET /api/todos/{id} 获取单个任务。"""
create_resp = await client.post("/api/todos", json={"title": "单个查询"})
todo_id = create_resp.json()["data"]["id"]
response = await client.get(f"/api/todos/{todo_id}")
assert response.status_code == 200
assert response.json()["data"]["title"] == "单个查询"
@pytest.mark.asyncio
async def test_api_get_todo_not_found(client):
"""测试 GET /api/todos/{id} 不存在的任务应返回 404。"""
response = await client.get("/api/todos/99999")
assert response.status_code == 404
@pytest.mark.asyncio
async def test_api_update_todo(client):
"""测试 PUT /api/todos/{id} 更新任务。"""
create_resp = await client.post("/api/todos", json={"title": "待更新"})
todo_id = create_resp.json()["data"]["id"]
response = await client.put(f"/api/todos/{todo_id}", json={
"title": "已更新",
"completed": True,
})
assert response.status_code == 200
assert response.json()["data"]["title"] == "已更新"
assert response.json()["data"]["completed"] is True
@pytest.mark.asyncio
async def test_api_delete_todo(client):
"""测试 DELETE /api/todos/{id} 删除任务。"""
create_resp = await client.post("/api/todos", json={"title": "待删除"})
todo_id = create_resp.json()["data"]["id"]
response = await client.delete(f"/api/todos/{todo_id}")
assert response.status_code == 200
# 再次查询应返回 404
get_resp = await client.get(f"/api/todos/{todo_id}")
assert get_resp.status_code == 404