第 13 章: FastAPI应用测试


本章概述

学习如何使用pytest为FastAPI应用编写单元测试。


13.1 pytest简介

pytest是Python的测试框架,简单易用:

安装

pip install pytest
pip install httpx  # 用于测试API

13.2 创建第一个测试

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"Hello": "World"}

运行测试:

pytest

13.3 使用pytest fixtures删除重复代码

import pytest

@pytest.fixture
def client():
    from main import app
    with TestClient(app) as c:
        yield c

def test_read_main(client):
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"Hello": "World"}

说明fixture是pytest的概念,用于提供测试前的准备工作。


13.4 测试用户模块

def test_create_user(client):
    response = client.post(
        "/users/",
        json={"username": "test", "password": "test123"}
    )
    assert response.status_code == 201
    data = response.json()
    assert data["username"] == "test"

def test_login(client):
    # 先创建用户
    client.post(
        "/users/",
        json={"username": "test", "password": "test123"}
    )
    
    # 登录
    response = client.post(
        "/token",
        data={"username": "test", "password": "test123"}
    )
    assert response.status_code == 200
    assert "access_token" in response.json()

13.5 测试任务模块

def test_create_task(client):
    # 先登录获取token
    client.post(
        "/users/",
        json={"username": "test", "password": "test123"}
    )
    response = client.post(
        "/token",
        data={"username": "test", "password": "test123"}
    )
    token = response.json()["access_token"]
    
    # 创建任务
    response = client.post(
        "/tasks/",
        json={"name": "Test Task"},
        headers={"Authorization": f"Bearer {token}"}
    )
    assert response.status_code == 201

def test_get_all_tasks(client):
    # 登录并创建任务...
    
    response = client.get(
        "/tasks/",
        headers={"Authorization": f"Bearer {token}"}
    )
    assert response.status_code == 200
    assert isinstance(response.json(), list)

13.6 测试数据库

使用独立的测试数据库:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from main import Base

# 测试数据库
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

@pytest.fixture
def db():
    # 创建测试数据库表
    Base.metadata.create_all(bind=engine)
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()
        # 删除测试数据库表
        Base.metadata.drop_all(bind=engine)

13.7 事件循环(Event Loop)

FastAPI支持异步测试:

import pytest
from httpx import AsyncClient

@pytest.mark.asyncio
async def test_async_endpoint():
    async with AsyncClient(app=app, base_url="http://test") as client:
        response = await client.get("/")
        assert response.status_code == 200

13.8 测试覆盖率和报告

pip install pytest-cov
pytest --cov=app --cov-report=html

这会生成HTML格式的测试覆盖率报告。


小结

在本章中,我们学习了: - ✅ 使用pytest编写测试 - ✅ 使用TestClient测试API - ✅ 使用fixtures管理测试依赖 - ✅ 测试用户认证 - ✅ 测试CRUD操作 - ✅ 使用测试数据库 - ✅ 异步测试 - ✅ 测试覆盖率报告


🎉 总结

恭喜!你已经完成了FastAPI的学习之路。现在你应该能够:

  • ✅ 创建FastAPI应用
  • ✅ 定义路由和参数
  • ✅ 使用Pydantic验证数据
  • ✅ 连接数据库
  • ✅ 使用模板引擎
  • ✅ 实现认证
  • ✅ 编写测试

下一步学习建议

  1. 部署FastAPI应用:学习如何使用Docker、Nginx部署
  2. WebSocket:FastAPI支持WebSocket实时通信
  3. GraphQL:使用Strawberry或Ariadne集成GraphQL
  4. 后台任务:使用Celery或ARQ处理后台任务
  5. 微服务:将FastAPI应用拆分为微服务架构

推荐资源

  • 官方文档:https://fastapi.tiangolo.com/
  • GitHub:https://github.com/tiangolo/fastapi
  • 示例项目:https://github.com/tiangolo/full-stack-fastapi-template

继续实践和探索,祝你在FastAPI的开发旅程中取得成功!🚀