用 pytest fixture 管理临时测试数据库

举报
yd_251192881 发表于 2026/10/30 00:18:44 2026/10/30
【摘要】 用 pytest 的 tmp_path 和 yield fixture 为每个测试创建独立的 SQLite 临时数据库,明确初始化、依赖和清理关系,避免测试之间互相污染。

测试数据库最容易出问题的地方,通常不是 SQL 写错,而是多个测试共用同一份数据。一个用例刚插入记录,另一个用例就假设表是空的;单独运行能通过,按顺序一起运行却失败。把数据库的创建、初始化和清理交给 pytest fixture,可以让每个测试拥有独立环境。

下面以一个待办事项表为例。先在项目的 conftest.py 中创建临时数据库:

import sqlite3

import pytest


@pytest.fixture
def db(tmp_path):
    connection = sqlite3.connect(tmp_path / "test.db")
    connection.executescript(
        """
        CREATE TABLE todo (
            id INTEGER PRIMARY KEY,
            title TEXT NOT NULL
        );
        """
    )

    try:
        yield connection
    finally:
        connection.close()

tmp_path 是 pytest 提供的内置 fixture。每次调用都会得到一个独立目录,测试结束后由 pytest 清理,因此不需要手写删除文件的逻辑。db fixture 使用 yield 把连接交给测试;无论测试成功还是抛异常,finally 都会执行,连接不会残留。

测试直接使用这个 fixture:

def test_create_todo(db):
    db.execute(
        "INSERT INTO todo (title) VALUES (?)",
        ("整理发布清单",),
    )
    db.commit()

    rows = db.execute(
        "SELECT title FROM todo"
    ).fetchall()

    assert rows == [("整理发布清单",)]

第二个测试查不到第一个测试的数据,因为两个测试拿到的是不同的临时数据库:

def test_todo_list_starts_empty(db):
    rows = db.execute(
        "SELECT title FROM todo"
    ).fetchall()

    assert rows == []

当多个测试都需要一组基础数据时,可以再增加一个依赖 db 的 fixture,而不要在 db 中自动塞数据:

@pytest.fixture
def todo_with_item(db):
    db.execute(
        "INSERT INTO todo (title) VALUES (?)",
        ("准备周报",),
    )
    db.commit()
    return db

这样只有显式声明 todo_with_item 的测试才会获得预置记录。普通数据库测试仍然从空表开始,数据准备关系也更清楚。不要把这类逻辑设成 autouse=True,否则所有测试都会被隐式修改,排查问题时很难看出数据来自哪里。

这套结构也方便扩展。需要更接近真实数据库时,可以在同一个 db fixture 中替换连接方式,但测试用例仍只依赖 fixture 返回的连接接口。团队最好把 fixture 放在共享的 conftest.py 中,把业务专用数据放到对应测试目录,避免所有场景都堆进一个全局 fixture。

临时数据库只能解决测试隔离,不能代替业务事务设计。需要验证回滚、并发或锁等待时,仍应编写针对性用例。但对大多数增删改查测试,tmp_path 加 yield 已经足够简单:每个测试从确定的起点开始,结束后自动释放资源,失败也不会污染下一次运行。

把测试从共享数据库中拆出来之后,执行顺序不再影响结果,开发者也能放心单独重跑失败的用例。这是 fixture 带来的直接价值。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。