Python 现代开发学习笔记

(二十二)用测试客户端核对页面与数据库

1. 每个测试独立准备数据库

# 项目文件:shelf_project/tests/conftest.py
import pytest
from bs4 import BeautifulSoup
from werkzeug.security import generate_password_hash

from shelfweb import create_app
from shelfweb.db import get_db, init_db


@pytest.fixture(scope="session")
def hashes():
    # 只复用计算出的摘要,登录仍经过真正的校验。
    return {name: generate_password_hash(f"learn-{name}") for name in ["alice", "bob"]}


@pytest.fixture
def app(tmp_path, hashes):
    application = create_app(
        {
            "TESTING": True,
            "SECRET_KEY": "only-for-tests",
            "DATABASE": str(tmp_path / "books.sqlite3"),
        },
        instance_path=tmp_path / "instance",
    )
    with application.app_context():
        init_db()
        connection = get_db()
        with connection:
            connection.executemany(
                "INSERT INTO users(username,password_hash) VALUES (?,?)", hashes.items()
            )
    return application


@pytest.fixture
def client(app):
    return app.test_client()


def csrf(client, path="/auth/login"):
    response = client.get(path)
    assert response.status_code == 200
    return BeautifulSoup(response.data, "html.parser").select_one(
        'input[name="csrf_token"]'
    )["value"]


def login(client, name="alice"):
    token = csrf(client)
    response = client.post(
        "/auth/login",
        data={"username": name, "password": f"learn-{name}", "csrf_token": token},
    )
    assert response.status_code == 303
    return response


def create(client, title="Python Web", **values):
    data = {
        "title": title,
        "tags": "基础, 网络",
        "csrf_token": csrf(client, "/books/new"),
        **values,
    }
    return client.post("/books/new", data=data)

TESTING=True 让未处理异常直接暴露给测试。这里仍注册了数据库和 HTTP 异常处理器,因此这些已经处理的失败依旧返回具体状态。

测试用 BeautifulSoup 从实际 HTML 取隐藏字段,再通过真实登录表单取得 Cookie。client 自动保存后续响应中的 Cookie,下一次请求继续发送。.get_cookie 可以核对 Cookie 是否改变,session_transaction 可以在测试中检查会话字段,或准备专门的状态。

2. 失败也核对记录与连接

测试链 核对的结果
新增 → 详情 → 修改 → 删除 状态、跳转、公开字段和最后的记录
保存后刷新 重复 GET,没有重复新增,flash 只显示一次
空白、过长、重复字段、附加归属 表单 422,不写入
同名新增或改名 409,原记录不变
bob 读取或修改 alice 的书 403,记录归属与内容保留
改坏 Cookie 签名 无法恢复登录,JSON 返回 401
退出后重放旧 Cookie 服务器登录记录已经删除,仍为 401
缺少、重复或旧 CSRF 令牌 400,不执行书籍写入
INSERT 已执行后注入数据库异常 500,事务回滚,下一请求记录数为零
同一请求多次取连接 复用一次,正常和失败结束后均关闭
新工厂打开相同文件 书籍和有效登录仍可恢复
# 在 shelf_project 目录执行本项目测试。
uv run python -m pytest -q

完整检查见 书籍测试、身份与转义测试 和 资源及重开测试。测试方法可以对照 Flask 测试文档。

测试先从真实页面读取令牌,提交后检查状态和 Location,再读取 HTML 或 JSON 验证最终记录,最后核对失败回滚和连接关闭

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