【pytest 】 pytest 生命周期
【pytest】编写自动化测试用例命名规范README
【python】连接Jira获取token以及jira对象
【python】解析自动化脚本文件并按照=测试周期=存储记录
【python】向Jira推送自动化用例执行成功
【python】向Jira测试计划下,附件中增加html测试报告
【pytest】获取所有用例名称并存于数据库
【Pytest】生成html报告中,中文乱码问题解决方案
【Pytest】将用例运行结果存储到数据库,以sqllite为例
文章目录
- pytest 生命周期
- 1. Fixture 的作用域与生命周期
- 2. 钩子函数与生命周期
- 会话级别钩子
- 收集阶段钩子
- 运行阶段钩子
- 3. Fixture 作用域层次图
- 4. 钩子函数执行顺序图
- 5. 完整生命周期流程(总结)
- 总结
pytest 生命周期
pytest 的生命周期主要由以下几个层次构成,范围从大到小:
- 测试会话(Session)生命周期:一次
pytest
命令的整个过程。 - 包/目录(Package)生命周期:针对每个测试目录(包含
__init__.py
的目录)。 - 模块(Module)生命周期:针对每个
.py
测试文件。 - 类(Class)生命周期:针对每个测试类(如果使用了测试类)。
- 函数/方法(Function/Method)生命周期:针对每个以
test_
开头的函数或方法。
这些生命周期的管理主要通过 Fixture 的 scope
参数和 钩子函数(Hooks) 来实现。
1. Fixture 的作用域与生命周期
Fixture 是理解 pytest 生命周期的关键。它的 scope
参数直接决定了它何时被创建和销毁。
作用域 | 描述 | 创建时机 | 销毁时机 |
---|---|---|---|
session | 整个测试会话 | 会话开始时创建一次 | 会话结束时销毁一次 |
package | 一个Python包(目录) | 包内第一个测试执行前 | 包内最后一个测试执行后 |
module | 一个Python模块(文件) | 模块内第一个测试执行前 | 模块内最后一个测试执行后 |
class | 一个测试类 | 类内第一个测试执行前 | 类内最后一个测试执行后 |
function | 一个测试函数(默认) | 每个测试函数执行前 | 每个测试函数执行后 |
示例:
# conftest.py文件
import pytest@pytest.fixture(scope="session")
def database_connection():# 在整个测试会话中只执行一次print("\n=== 建立数据库连接(session)===")conn = "模拟的连接对象"yield connprint("=== 关闭数据库连接(session)===")@pytest.fixture(scope="module")
def setup_module_data():# 在每个测试模块中只执行一次print("\n--- 初始化模块数据(module)---")data = {"module": "data"}yield dataprint("--- 清理模块数据(module)---")@pytest.fixture(scope="function")
def reset_state():# 在每个测试函数中都会执行print("> 重置状态(function)")yieldprint("> 清理状态(function)")
# test_demo.py 文件
def test_one(database_connection, setup_module_data, reset_state):assert database_connection is not Noneassert "module" in setup_module_dataprint("执行 test_one")def test_two(database_connection, setup_module_data, reset_state):assert database_connection is not Noneassert "module" in setup_module_dataprint("执行 test_two")
运行上述测试的输出可能如下:
=== 建立数据库连接(session)===--- 初始化模块数据(module)---
> 重置状态(function)
执行 test_one
.> 清理状态(function)
> 重置状态(function)
执行 test_two
.> 清理状态(function)
--- 清理模块数据(module)---=== 关闭数据库连接(session)===
从输出可以清晰地看到不同作用域的 fixture 是如何在生命周期中被调用的。
2. 钩子函数与生命周期
钩子函数允许你在 pytest 生命周期的特定时刻插入自己的代码。它们通常定义在 conftest.py
文件或自定义插件中。
以下是一些关键的、与生命周期相关的钩子函数:
会话级别钩子
pytest_sessionstart(session)
: 在测试会话开始之前执行。pytest_sessionfinish(session, exitstatus)
: 在测试会话结束之后执行,即使发生异常也会执行。
收集阶段钩子
pytest_collection_modifyitems(config, items)
: 在测试用例收集完毕之后被调用,可以用来对测试用例进行排序、过滤等操作。pytest_collection_finish(session)
: 测试收集完全结束时调用。
运行阶段钩子
pytest_runtest_protocol(item, nextitem)
: 控制每个测试项的运行流程。pytest_runtest_setup(item)
: 在每个测试项执行之前运行(在 fixture 之前)。pytest_runtest_call(item)
: 调用测试项(执行测试函数本身)。pytest_runtest_teardown(item, nextitem)
: 在每个测试项执行之后运行(在 fixture 之后)。pytest_fixture_setup(fixturedef, request)
: 在执行一个 fixture 的设置代码时调用。pytest_fixture_post_finalizer(fixturedef, request)
: 在 fixture 的清理代码执行后调用。
示例:使用钩子函数
# conftest.py文件
def pytest_sessionstart(session):print("🔥 pytest 会话开始!")def pytest_sessionfinish(session, exitstatus):print(f"✅ pytest 会话结束!退出状态码:{exitstatus}")def pytest_collection_modifyitems(config, items):print(f"📋 收集到了 {len(items)} 个测试用例")# 例如:反转测试顺序(不推荐在生产中使用)# items.reverse()def pytest_runtest_setup(item):print(f"🛠️ 准备设置:{item.name}")def pytest_runtest_teardown(item, nextitem):print(f"🧹 执行清理:{item.name}")
3. Fixture 作用域层次图
4. 钩子函数执行顺序图
5. 完整生命周期流程(总结)
一次典型的 pytest
命令执行会经历以下阶段:
- 会话开始
- 调用
pytest_sessionstart
钩子。 - 创建
scope="session"
的 fixture。
- 调用
- 测试收集
- 递归遍历指定目录,寻找
test_*.py
文件和*_test.py
文件。 - 在这些文件中,收集
Test
开头的类(不含__init__
方法)和test_
开头的函数/方法。 - 调用
pytest_collection_modifyitems
等收集钩子。
- 递归遍历指定目录,寻找
- 测试执行(对每个测试项循环)
a. Package/Module 级别 Setup:
* 如果进入一个新的包/模块,创建scope="package"
/"module"
的 fixture。
b. Class 级别 Setup:
* 如果测试项在一个类中,且是类中的第一个测试,创建scope="class"
的 fixture。
c. Test Setup:
* 调用pytest_runtest_setup
钩子。
* 创建scope="function"
的 fixture。
d. Test Execution:
* 调用pytest_runtest_call
钩子,执行测试函数本身的代码。
e. Test Teardown:
* 销毁scope="function"
的 fixture(执行yield
之后的代码或addfinalizer
注册的函数)。
* 调用pytest_runtest_teardown
钩子。
f. Class/Package/Module 级别 Teardown:
* 当一个类/模块/包内的所有测试都执行完毕后,销毁对应的scope="class"
/"module"
/"package"
的 fixture。 - 会话结束
- 销毁所有
scope="session"
的 fixture。 - 调用
pytest_sessionfinish
钩子。 - 生成测试报告。
- 销毁所有
总结
- Fixture 作用域 是控制资源创建和销毁粒度的主要手段。
- 钩子函数 让你能在生命周期的精确时刻介入,实现自定义行为。
- 理解生命周期有助于你:
- 优化测试速度:将昂贵的操作(如启动数据库)设置为
session
或module
级别。 - 确保测试隔离:正确使用
function
级别的 fixture 来保证测试不相互影响。 - 实现复杂的 setup/teardown 逻辑,如全局初始化和清理。
- 优化测试速度:将昂贵的操作(如启动数据库)设置为
通过结合使用 Fixture 和钩子函数,你可以非常灵活地掌控 pytest 的整个测试流程。