pytest 实践
实验目标
编写完整的测试套件,覆盖 API 的各个功能点。
实验 1:基础测试结构
安装依赖:
bash
pip install pytest pytest-cov httpx创建 test_main.py:
python
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}运行测试:
bash
pytest
pytest -v # 详细输出
pytest -s # 显示 print 输出实验 2:参数化测试
python
import pytest
@pytest.mark.parametrize("user_id,expected_status", [
(1, 200),
(999, 404),
])
def test_get_user(user_id, expected_status):
response = client.get(f"/users/{user_id}")
assert response.status_code == expected_status
@pytest.mark.parametrize("email,username,password,expected_status", [
("valid@example.com", "validuser", "password123", 201),
("invalid-email", "user", "password", 422),
("", "user", "password", 422),
])
def test_create_user_validation(email, username, password, expected_status):
response = client.post("/users/", json={
"email": email,
"username": username,
"password": password
})
assert response.status_code == expected_status实验 3:Fixture 使用
python
import pytest
@pytest.fixture
def created_user():
response = client.post("/users/", json={
"email": "fixture@example.com",
"username": "fixtureuser",
"password": "password123"
})
return response.json()
def test_get_created_user(created_user):
user_id = created_user["id"]
response = client.get(f"/users/{user_id}")
assert response.status_code == 200
assert response.json()["email"] == "fixture@example.com"
def test_delete_created_user(created_user):
user_id = created_user["id"]
response = client.delete(f"/users/{user_id}")
assert response.status_code == 204实验 4:异步测试
python
import pytest
from httpx import AsyncClient
from main import app
@pytest.mark.asyncio
async def test_async_endpoint():
async with AsyncClient(app=app, base_url="http://test") as ac:
response = await ac.get("/users/")
assert response.status_code == 200实验 5:Mock 外部依赖
python
from unittest.mock import patch, MagicMock
def test_external_api_call():
with patch('main.external_api_call') as mock_api:
mock_api.return_value = {"data": "mocked"}
response = client.get("/external-data")
assert response.status_code == 200
assert response.json() == {"data": "mocked"}
mock_api.assert_called_once()实验 6:数据库测试
python
@pytest.fixture(scope="function")
def test_db():
# 创建测试数据库
Base.metadata.create_all(bind=engine)
yield
# 清理测试数据库
Base.metadata.drop_all(bind=engine)
def test_user_crud(test_db):
# Create
response = client.post("/users/", json={
"email": "crud@example.com",
"username": "cruduser",
"password": "password123"
})
assert response.status_code == 201
user_id = response.json()["id"]
# Read
response = client.get(f"/users/{user_id}")
assert response.status_code == 200
# Update
response = client.put(f"/users/{user_id}", json={
"email": "updated@example.com",
"username": "updateduser"
})
assert response.status_code == 200
# Delete
response = client.delete(f"/users/{user_id}")
assert response.status_code == 204验收标准
✅ 所有测试通过
✅ 测试覆盖率 > 80%
✅ 正常和异常情况都有测试
✅ 使用 fixture 复用测试数据
✅ 参数化测试减少重复代码
返回第四章概览