pytest 如何在所有测试类之前运行一次方法

用 scope="session" 的 fixture 复用会话级初始化;默认首次被依赖时执行,autouse 可让可见测试自动依赖。参数化和 xdist worker 需要额外区分。

最佳实践
测试检测与质量验证插画

一句话回答:定义一个 scope="session" 的 fixture——未参数化时,它在首次被测试依赖时创建,并在当前测试进程会话内复用,不一定在会话启动时执行。把它放在项目根目录的 conftest.py 里可被该目录及子目录下的测试发现,不需要在测试文件 import;想让所有测试自动用它(不写参数)就加 autouse=True。

标准写法

# conftest.py(放在测试根目录)
import pytest

@pytest.fixture(scope="session")
def global_setup():
    # 首次有测试依赖该 fixture 时初始化
    print("初始化:建测试数据库、起服务……")
    yield
    # 全部测试结束后执行一次(清理)
    print("清理:释放资源")

fixture 里 yield 之前是 setup,之后是 teardown。若 setup 在 yield 前失败,其后清理段不会执行;已经创建的外部资源应使用上下文管理器或适当的 finalizer 保护。表中的执行频率按未参数化、单进程情况描述;参数化可能导致同一作用域内多次创建。

作用域对照表

scope 执行频率 典型用途
function(默认) 每个测试函数一次 临时数据、mock
class 每个测试类一次 类级资源
module 每个 py 文件一次 模块级连接
package 每个包一次 包级初始化
session 单进程会话内复用 ⭐ 全局一次性初始化

两种使用方式

显式依赖(测试声明需要它):

def test_something(global_setup):
    ...

自动生效(autouse,测试无感知):

@pytest.fixture(scope="session", autouse=True)
def global_setup():
    ...

一次性的环境初始化(建库、起容器、写配置)通常用 autouse + session 组合。

配套技巧:每次测试前重置数据

以下是放在 conftest.py 中的 SQLite 简化示例:session 级建资源、function 级清数据。示例不等同于真实服务的事务隔离方案。

import sqlite3
import pytest

@pytest.fixture(scope="session")
def db_connection():
    conn = sqlite3.connect(":memory:")
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
    yield conn
    conn.close()

@pytest.fixture(autouse=True)
def reset_table(db_connection):
    db_connection.execute("DELETE FROM users")
    db_connection.commit()

常见问题(FAQ)

Q:fixture 写在测试文件里和 conftest.py 里有区别吗?

A:作用范围不同。测试文件里的 fixture 只对该文件可见;conftest.py 里的对该目录及子目录全部可见。全局性 fixture 放根 conftest.py。

Q:xdist 并行时 session fixture 会跑几次?

A:每个 worker 进程各跑一次(session 是进程级概念)。真正的"全局只跑一次"(如建共享数据库)需要文件锁或 pytest-xdist 的 FileLock 方案协调。

Q:unittest 风格的 setUpClass 和 fixture 怎么选?

A:pytest 项目统一用 fixture——可组合、有 teardown、支持参数化;setUpClass 每个类都跑一次,做不到真正的"全局一次"。混用容易乱,迁移期例外。

核查依据

本文依据官方文档核对,示例未在实际业务环境运行;上线前请按部署版本、权限与数据范围验证。


延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台