Python 现代开发学习笔记

(二十三)用接口测试检查输入、权限与持久化

1. 每个测试使用自己的数据库

第六章已经用 pytest 检查文件和事务,这里把检查入口换成 HTTP。临时目录建立 SQLite 文件,with TestClient(...) 保证应用启动与收尾,账号摘要在整组测试中计算一次。

# 项目文件:api_project/tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from werkzeug.security import generate_password_hash

from bookapi.app import create_app
from bookapi.config import Settings
from bookapi.models import User


@pytest.fixture(scope="session")
def password_hashes():
    # 整组测试复用摘要,仍由真正的密码校验函数检查登录。
    return {name: generate_password_hash(f"learn-{name}") for name in ["alice", "bob"]}


@pytest.fixture
def app(tmp_path, password_hashes):
    application = create_app(Settings(tmp_path / "books.sqlite3"))
    with TestClient(application) as client:
        with application.state.session_factory.begin() as session:
            session.add_all(
                [
                    User(username=name, password_hash=value)
                    for name, value in password_hashes.items()
                ]
            )
        yield application, client


def login(client, username="alice"):
    response = client.post(
        "/auth/login", json={"username": username, "password": f"learn-{username}"}
    )
    assert response.status_code == 200
    return {"Authorization": f"Bearer {response.json()['access_token']}"}


@pytest.fixture
def alice(app):
    return login(app[1])


@pytest.fixture
def bob(app):
    return login(app[1], "bob")

login 通过真实登录路由取得令牌,测试继续通过请求头发送。读取、修改和权限判断都经过实际依赖链,没有把当前用户替换成固定值。

测试内容见 书籍与输入测试、账号测试 和 资源、异常与重开测试。它们分别核对:

过程 观察结果
新增 → 读取 → 分页 → 部分更新 → 删除 状态、字段、Location 与最后的记录
错误类型、空白书名、附加归属、null 422,记录数量和内容保持不变
两个账号管理同名书与交叉修改 各自可保存,同一编号的越权操作被拒绝
同名新增与同名改名 409,之后仍可读取原有记录
到期、退出和缺少令牌 401 和认证提示头
数据库 INSERT 执行后发生异常 500,新会话核对记录没有留下
一条请求的数据库依赖复用 只创建一份会话,正常和失败均收尾
关闭应用再打开同一个文件 账号、有效令牌和书籍均能恢复
后台导出与另一用户读取 完成结果可读,归属不同得到 403
# 在 api_project 中运行整组测试。
uv run python -m pytest -q
测试先预测 HTTP 和数据库结果,执行请求后读响应,再通过下一请求或新会话核对记录,失败用例也检查事务回滚与资源归还

2. 覆盖依赖时保留核验对象

框架提供 app.dependency_overrides[原函数] = 替代函数,替换某项依赖。配套资源测试只在 get_session 外包一层记录动作的生成器;认证仍校验真实令牌,业务仍访问临时 SQLite。身份依赖和路由共同请求这项资源,记录中只出现一次 open 和一次 exit。

依赖覆盖在 finally 中清空,让后面的测试使用原来的配置。请求本身出错时,也核对连接已经归还。这里检查的是资源生命周期与失败状态,避免测试只根据返回 200 判断程序正常。

笔记正文与全部题解 · Ctrl / ⌘ K