conftest.py
是 pytest 框架中用于共享测试配置的核心文件,支持层级化管理和自动发现机制。以下是其核心作用及用法详解:
1. 共享 Fixture
作用:定义公共测试夹具(Fixture),供多个测试模块复用,避免重复代码。
示例:
# conftest.py import pytest @pytest.fixture(scope="session") def database_connection(): conn = create_db_connection() yield conn conn.close()
使用范围:
同级目录及所有子目录的测试文件均可使用该 Fixture。
不同层级的
conftest.py
中 Fixture 按就近原则覆盖。
作用域
- function默认作用域
- class
- module
- package
- session
-
setup
函数和teardown函数
如果想在测试用例或者测试类执行前后都加上重复执行的代码,例如:
使用setup
函数完成初始化测试环境:在测试用例执行前完成准备工作,例如创建数据库连接、生成测试数据、启动浏览器等;
使用teardown函数完成清理测试环境:在测试用例执行后释放资源,例如关闭数据库连接、删除临时文件、释放内存
pytest 支持多层级作用域,不同层级的 setup/teardown 按以下顺序执行:
会话级(Session)
通过 setup_session/teardown_session 实现,整个测试会话(所有模块)执行一次。
适用场景:全局资源初始化(如启动服务集群)。
模块级(Module)
使用 setup_module/teardown_module,单个 .py 文件执行前后各运行一次。
示例:加载测试数据。
类级(Class)
通过 setup_class/teardown_class 实现,每个测试类执行一次。
适用场景:初始化类内共享资源(如日志对象、API 请求客户端)。
方法级(Method)
使用 setup_method/teardown_method,每个测试方法(类中的函数)执行前后运行。
示例每个用例创建独立浏览器实例。
函数级(Function)
通过 setup_function/teardown_function 实现,适用于类外的独立测试函数。
适用场景:函数级数据准备(如参数化测试输入)
代码demo如下:
class TestCase():
def setup_class(self):
print("====整个测试类开始前只执行一次setup_class====")
def teardown_class(self):
print("====整个测试类结束后只执行一次teardown_class====")
def setup_method(self):
print("==类里面每个用例执行前都会执行setup_method==")
def teardown_method(self):
print("==类里面每个用例结束后都会执行teardown_method==")
def test_1(self):
print("测试功能点1")
def test_2(self):
print("测试功能点2")
if __name__ == '__main__':
pytest.main(["-q", "-s"])
输出
============================= test session starts =============================
collecting ... collected 2 items
test_fixture1.py::TestCase::test_1 ====整个测试类开始前只执行一次setup_class====
==类里面每个用例执行前都会执行setup_method==
PASSED [ 50%]测试功能点1
==类里面每个用例结束后都会执行teardown_method==
test_fixture1.py::TestCase::test_2 ==类里面每个用例执行前都会执行setup_method==
PASSED [100%]测试功能点2
==类里面每个用例结束后都会执行teardown_method==
====整个测试类结束后只执行一次teardown_class====
============================== 2 passed in 0.03s ==============================
使用conftest.py实现setup
函数和teardown函数的功能
在conftest.py编写代码如下:
import pytest
@pytest.fixture(scope="function")
def fixture_method():
print("==类里面每个用例执行前都会执行setup_method==")
yield
print("==类里面每个用例结束后都会执行teardown_method==")
@pytest.fixture(scope="class")
def fixture_class():
print("====整个测试类开始前只执行一次setup_class====")
yield
print("====整个测试类结束后只执行一次teardown_class====")
测试用例py文件代码如下:
import pytest
class TestCase():
def test_1(self,fixture_method,fixture_class):
print("测试功能点1")
def test_2(self,fixture_method,fixture_class):
print("测试功能点2")
if __name__ == '__main__':
pytest.main(["-q", "-s"])
很显然测试用例中的代码看起来,清爽了很多很多,执行代码会有同样的效果
2. 层级化配置
目录结构示例:
project/ ├── conftest.py # 作用范围:全局 └── tests/ ├── conftest.py # 作用范围:tests 目录 └── subdir/ ├── conftest.py # 作用范围:subdir 目录 └── test_b.py
优先级:子目录的
conftest.py
优先级高于父目录,同名 Fixture 会被覆盖。
3. 钩子函数(Hooks)
自定义 pytest 行为:Pytest 提供了丰富的钩子函数(Hook),允许在测试生命周期不同阶段进行自定义扩展。
关于钩子函数,大家可以参考文章:
4. 自动发现机制
文件名固定:必须命名为
conftest.py
,否则 pytest 无法识别。无需导入:Fixture 和钩子函数会被 pytest 自动发现,测试文件直接通过名称引用。
5. 其他用途
插件加载:在
conftest.py
中初始化插件或外部库。全局配置:设置全局变量、环境变量或模拟外部服务。
示例场景
假设需要为 API 测试提供鉴权 Token:
# conftest.py import pytest @pytest.fixture(scope="module") def auth_token(): token = get_token_from_api() return token
测试文件直接使用:
# test_api.py def test_user_profile(auth_token): headers = {"Authorization": f"Bearer {auth_token}"} response = call_api(headers) assert response.status_code == 200
总结
核心价值:通过
conftest.py
实现测试配置的模块化、复用和层级管理。适用场景:共享 Fixture、自定义钩子、环境配置、插件集成等。
最佳实践:将通用配置放在高层级
conftest.py
,局部配置放在子目录中。