pytest初始化清除【pytest】

pytest 中的初始化与清理机制详解

在自动化测试中,初始化与清理操作(setup/teardown) 扮演着至关重要的角色,能够为测试环境的复用、资源的回收和测试隔离提供基础保障。 pytest支持多种粒度的初始化与清除: 模块级、类级、方法级 以及 目录级(通过 fixture 实现),下面分别进行介绍。


一、模块级初始化与清理

模块级别setupteardown 是在一个 .py 文件中所有测试类和函数执行之前和之后分别运行一次,适用于为整个模块准备公共资源或环境。

示例代码如下:

python 复制代码
def setup_module():
    print('\n *** 初始化-模块 ***')

def teardown_module():
    print('\n *** 清除-模块 ***')

class Test_错误密码:
    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1

    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2

    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2

class Test_错误密码2:
    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1

    def test_C001022(self):
        print('\n用例C001022')
        assert 2 == 2

执行命令:

复制代码
python -m pytest cases -s

运行结果显示模块级初始化和清理各执行一次,分别位于所有用例执行之前与之后,说明模块级 setup_moduleteardown_module 仅调用一次,适合用于准备共享数据或环境。


二、类级初始化与清理

类级别setup_classteardown_class 是在某个测试类的所有方法执行前后调用一次,适用于该类内部所有用例共享的资源管理。

示例:

python 复制代码
class Test_错误密码:
    @classmethod
    def setup_class(cls):
        print('\n === 初始化-类 ===')

    @classmethod
    def teardown_class(cls):
        print('\n === 清除 - 类 ===')

    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1

    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2

    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2

类级 setupteardown 在类内所有测试方法执行前后分别运行一次,用于初始化类内资源,如数据库连接或文件句柄等。


三、方法级初始化与清理

方法级别setup_methodteardown_method 是在类中每个测试方法执行前后都会调用,适用于方法之间不能共享状态的情况。

示例代码如下:

python 复制代码
class Test_错误密码:
    @classmethod
    def setup_class(cls):
        print('\n === 初始化-类 ===')

    @classmethod
    def teardown_class(cls):
        print('\n === 清除 - 类 ===')

    def setup_method(self):
        print('\n --- 初始化-方法 ---')

    def teardown_method(self):
        print('\n --- 清除-方法 ---')

    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1

    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2

    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2

此机制确保每个测试用例的执行都是"独立"的,彼此之间不会影响状态,便于发现依赖或污染问题。


四、目录级初始化与清理(使用 fixture 实现)

在更高的粒度下,pytest 提供了通过 fixture 实现 包或目录级别 的 setup/teardown 功能,通常定义在 conftest.py 中。

示例:

python 复制代码
# 文件路径: cases/conftest.py
import pytest

@pytest.fixture(scope='package', autouse=True)
def st_emptyEnv():
    print(f'\n#### 初始化-目录甲')
    yield
    print(f'\n#### 清除-目录甲')

解释:

  • scope='package' 指定了初始化作用范围是整个包(即目录);
  • autouse=True 表示不需要在测试用例中显式引用该 fixture,它会自动生效;
  • yield 语句前是初始化代码,yield 后是清理代码。

注意: 当前 pytest 在该机制中存在一个缺陷 ------ 清理代码(yield 之后的部分)并不一定会在"该目录下最后一个用例执行完成后"立即调用。也就是说,某些资源可能未及时释放,从而影响其他目录下的测试行为。

该问题已被用户反馈至 pytest 的 GitHub issue 追踪系统,详情可点击查看:Bug Report

因此,在该问题未修复之前,建议暂时避免依赖目录级别的清理机制,尤其是在有状态污染风险的测试场景中。


总结

|--------|------------------------------------|----------|----------------------|
| 级别 | 函数/方法名 | 调用频次 | 适用场景 |
| 模块级 | setup_module / teardown_module | 每个模块一次 | 整体资源初始化,如数据库连接池 |
| 类级 | setup_class / teardown_class | 每个类一次 | 类内资源初始化,如 API 会话 |
| 方法级 | setup_method / teardown_method | 每个测试函数一次 | 保证测试之间完全隔离 |
| 目录(包)级 | @pytest.fixture(scope="package") | 整个目录一次 | 多模块共享资源(当前有 bug,不推荐) |