pytest 中的初始化与清理机制详解
在自动化测试中,初始化与清理操作(setup/teardown)扮演着至关重要的角色,能够为测试环境的复用、资源的回收和测试隔离提供基础保障。pytest
支持多种粒度的初始化与清除:模块级、类级、方法级以及目录级(通过 fixture 实现),下面分别进行介绍。
一、模块级初始化与清理
模块级别的 setup
和 teardown
是在一个 .py
文件中所有测试类和函数执行之前和之后分别运行一次,适用于为整个模块准备公共资源或环境。
示例代码如下:
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_module
与 teardown_module
仅调用一次,适合用于准备共享数据或环境。
二、类级初始化与清理
类级别的 setup_class
和 teardown_class
是在某个测试类的所有方法执行前后调用一次,适用于该类内部所有用例共享的资源管理。
示例:
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
类级 setup
和 teardown
在类内所有测试方法执行前后分别运行一次,用于初始化类内资源,如数据库连接或文件句柄等。
三、方法级初始化与清理
方法级别的 setup_method
和 teardown_method
是在类中每个测试方法执行前后都会调用,适用于方法之间不能共享状态的情况。
示例代码如下:
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
中。
示例:
# 文件路径: 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。
因此,在该问题未修复之前,建议暂时避免依赖目录级别的清理机制,尤其是在有状态污染风险的测试场景中。
总结
级别 |
函数/方法名 |
调用频次 |
适用场景 |
模块级 |
|
每个模块一次 |
整体资源初始化,如数据库连接池 |
类级 |
|
每个类一次 |
类内资源初始化,如 API 会话 |
方法级 |
|
每个测试函数一次 |
保证测试之间完全隔离 |
目录(包)级 |
|
整个目录一次 |
多模块共享资源(当前有 bug,不推荐) |