Skip to content

测试与调试

TestClient、pytest、依赖覆盖、覆盖率。

Updated View as Markdown
For humans

测试与调试

FastAPI 的测试栈:pytest + TestClient + dependency_overrides。面试主线:测试怎么起、依赖怎么替换、覆盖率怎么看。

TestClient

from fastapi.testclient import TestClient

def test_get_user():
    with TestClient(app) as client:          # with: 触发 lifespan
        resp = client.get("/users/1")
    assert resp.status_code == 200
    assert resp.json()["name"] == "alice"
  • TestClient 基于 httpx,同步调用接口,不用起服务
  • with 块触发应用生命周期(lifespan 启动/关闭),测数据库集成必须用
  • 断言状态码、响应体、响应头

pytest 组织

# conftest.py
import pytest
from fastapi.testclient import TestClient

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

# test_users.py
def test_create_user(client):
    resp = client.post("/users", json={"name": "alice", "email": "a@b.c"})
    assert resp.status_code == 201
  • conftest.py 放共享 fixture,pytest 自动发现
  • 测试函数命名 test_ 前缀,文件 test_*.py
  • fixture 的 yield 形式管理资源(测试后清理)

依赖覆盖:测数据库

def override_get_db():
    yield MemoryDB()          # 或测试库会话

app.dependency_overrides[get_db] = override_get_db

def test_list_users(client):
    resp = client.get("/users")
    assert resp.status_code == 200
  • 把真实数据库依赖换成内存/测试库,业务代码零改动
  • 同理可替换:外部 API 客户端(mock)、鉴权依赖(固定用户)、发邮件
  • 测试完 clear() 恢复,或每个测试重新设置

覆盖率与调试

pytest --cov=app --cov-report=term-missing    # 覆盖率报告
  • 覆盖率是手段不是目标:核心业务逻辑(鉴权、金额计算、状态流转)必须覆盖,模板和配置别凑数
  • 调试手段:print/日志、pytest -s(不捕获输出)、IDE 断点、--reload 开发热重载
  • 慢查询排查:日志里打 SQL 执行时间;生产用 APM

测试金字塔:单元测试(函数逻辑)为主,接口测试(TestClient)覆盖关键路径,端到端测试少量。FastAPI 的依赖覆盖让接口测试成本很低,多写。

面试追问

  1. TestClient 怎么用? httpx 基的同步客户端,with 块触发 lifespan。不用起真实服务
  2. 怎么测数据库相关接口? dependency_overrides 把 get_db 换成测试库/内存实现。业务代码零改动
  3. fixture 是什么? pytest 的资源管理:conftest.py 共享,yield 形式清理。测试间复用
  4. 覆盖率多少合适? 核心逻辑重点覆盖,别追数字。鉴权、金额、状态机必测
  5. 异步代码怎么测? TestClient 内部处理事件循环;纯异步函数用 pytest-asyncio 或 asyncio.run
Navigation

Type to search…

↑↓ navigate↵ selectEsc close