📝 面试求职: 「面试试题小程序」 ,内容涵盖 测试基础、Linux操作系统、MySQL数据库、Web功能测试、接口测试、APPium移动端测试、Python知识、Selenium自动化测试相关、性能测试、性能测试、计算机网络知识、Jmeter、HR面试,命中率杠杠的。(大家刷起来…)
📝 职场经验干货:
今天,我想和大家深入聊聊我们日常工作中广泛使用的 Python 测试框架——Pytest,特别是它核心的用例查找(Test Discovery)机制。
Pytest 之所以如此受欢迎,除了其简洁的断言、强大的 Fixture 系统外,其“约定优于配置”的用例自动发现能力也是关键因素之一。
我们通常只需要按照简单的规则编写测试文件和函数,运行 pytest 命令,它就能精确地找到并执行所有测试。
在这背后,隐藏着一套精密且可定制的规则和流程。
理解这套机制,不仅能帮助我们更高效地组织测试代码,还能在遇到“用例找不到”或“不期望的用例被执行”等问题时,快速定位并解决。
本文将带你深入 Pytest 的内部,详细剖析其用例查找的全过程,包括默认规则、查找流程、定制化配置以及常见问题排查。
准备好了吗?让我们开始这场探索之旅!文章较长,干货满满,建议收藏备用。
文章导览
1. 什么是测试用例发现(Test Discovery)?
2. Pytest 的默认用例发现规则
3. Pytest 用例发现的内部流程:深入 Collection Phase(收集阶段)
4. 定制化你的测试发现规则
5. 常见问题与排查技巧(Troubleshooting)
6. 总结与最佳实践
7.结语
什么是测试用例发现
(Test Discovery)
在软件测试自动化中,测试用例发现指的是测试框架自动识别项目中哪些代码是测试用例,并将它们收集起来准备执行的过程。
相比于需要手动注册每个测试用例的古老方法(例如,某些单元测试框架需要你将测试方法添加到一个测试套件中),自动发现极大地提高了效率,尤其是在大型项目中。
Pytest 的设计哲学之一就是减少样板代码,让测试编写更自然、更符合 Pythonic 风格。它的自动发现机制正是这一哲学的体现。
Pytest 的默认用例发现规则
Pytest 的核心魅力在于其强大的默认约定。如果你遵循这些约定,通常无需任何额外配置。
以下是 Pytest 查找测试用例时遵循的标准规则:
1. 起始点:
(Starting Point)
-
如果你在命令行中没有指定任何目录或文件参数,Pytest 会从当前工作目录开始查找。
-
如果你指定了文件或目录(例如 pytest tests/ 或 pytest test_login.py),Pytest 会从指定的路径开始查找。
-
Pytest 会递归地进入它找到的目录进行搜索。
2. 目录递归:
(Directory Recursion)
Pytest 会递归遍历所有子目录,除非目录名符合 norecursedirs 的配置(默认为 ., build, dist, CVS, _darcs, {arch}, .egg, venv, .git, .hg, .tox 等)。
这意味着以 . 开头的隐藏目录、常见的构建输出目录和虚拟环境目录默认会被忽略。
3. 测试文件识别:
(Test File)
Pytest 会查找符合 python_files 配置 glob 模式的文件。默认情况下,它会查找名为 test_.py 或 _test.py 的 Python 文件。
4. 测试类识别:
(Test Class)
在找到的测试文件中,Pytest 会查找符合 python_classes 配置名称模式的类。默认情况下,它会查找以 Test 开头的类(例如 class TestLogin:)。
重要:
Pytest 不会将在包含 __init__ 方法的类视为测试类。
这是为了防止将普通的业务逻辑类或基类误识别为测试集合。
如果你的测试类确实需要 __init__ 方法(虽然不常见,通常 Fixture 是更好的选择),你需要确保基类不以 Test 开头,或者通过其他方式组织。
5. 测试函数/方法识别:
(Test Function/Method)
在测试文件(模块级别)或测试类内部,Pytest 会查找符合 python_functions 配置名称模式的函数或方法。
默认情况下,它会查找以 test_ 开头的函数或方法(例如 def test_login_success(): 或 def test_invalid_password(self):)。
总结一下默认规则:
-
文件: test_.py 或 _test.py
-
类: Test (且不能有 __init__ 方法)
-
函数/方法: test_
只要你的测试代码遵循这些简单的命名约定,Pytest 就能自动发现它们。
Pytest 用例发现的内部流程:
深入Collection Phase(收集阶段)
当我们运行 pytest 命令时,它首先进入的是 Collection Phase(收集阶段)。
这个阶段的目标就是根据上述规则(或自定义规则)找到所有的测试项(Test Items)。
这个过程大致可以分为以下几个步骤:
1. 初始化与配置加载:
Pytest 启动,加载命令行参数、pytest.ini / pyproject.toml / setup.cfg 配置文件以及所有 conftest.py 文件。
配置信息(包括发现规则的定制)会影响后续的收集行为。
2. 根节点与起始路径:
Pytest 确定一个或多个文件系统路径作为收集的起点(基于命令行参数或当前目录)。
每个起点对应一个 FSCollector(文件系统收集器)或 Session 根收集器。
3. 递归收集(Recursive Collection):
-
从起始路径开始,Pytest 递归地遍历目录结构。
-
对于每个遇到的目录和文件,Pytest 会尝试为其创建一个 Collector 节点。
目录 Collector
如果目录是一个 Python 包(包含 __init__.py,虽然对于测试目录非必需,但影响导入),它可能被视为 Package 节点;
否则是普通的 Directory 节点。Collector 会继续递归其子项。
文件 Collector
当遇到一个 Python 文件 (.py) 时,
Pytest 会调用 pytest_collect_file 钩子(Hook)。
默认实现会检查文件名是否匹配 python_files 模式。如果匹配,则创建一个 Module Collector 节点。
这个 Module 节点负责收集该文件内部的测试项。
非 Python 文件
Pytest 也可以通过插件或钩子收集非 .py 文件中的测试(例如 .yaml 文件定义的测试场景),但这超出了默认行为。
4. 模块内收集 (Module Collector):
-
Module 节点会导入对应的 Python 文件。
-
它会遍历模块的全局命名空间,查找符合条件的类和函数:
查找测试类
检查每个类名是否匹配 python_classes 模式,并且该类是否没有 __init__ 方法。
如果匹配,则创建一个 Class Collector 节点。
查找测试函数
检查每个函数名是否匹配 python_functions 模式。
如果匹配,则直接创建一个 Function Item 节点(这是一个最终的测试项,不是 Collector)。
5. 类内收集 (Class Collector):
-
Class 节点负责收集其内部的测试方法。
-
它会实例化测试类(如果需要,例如使用 Fixture),然后遍历类的属性。
-
检查每个方法名是否匹配 python_functions 模式。如果匹配,则创建一个 Function Item 节点(通常称为测试方法)。
对于同一个类,可能会根据参数化(Parametrization)生成多个 Function Item 节点。
6. 生成测试项(Test Items)与 Node ID:
-
收集过程的最终产物是一系列的 Test Item 节点(主要是 Function 节点)。每个 Item 代表一个独立的、可执行的测试单元。
-
Pytest 为每个收集到的节点(包括 Collector 和 Item)分配一个唯一的 Node ID。
Node ID 是一个字符串,通常反映了测试项在项目结构中的路径,
例如:tests/unit/test_auth.py::TestLogin::test_valid_credentials。
这个 ID 非常重要,用于测试报告、选择性执行 (-k 选项)、以及内部跟踪。
7. 收集后处理 :
(pytest_collection_modifyitems)
在所有测试项初步收集完毕后,Pytest 会调用 pytest_collection_modifyitems 钩子。
这个钩子允许插件或 conftest.py 对收集到的测试项列表进行修改,例如:
过滤
移除不满足特定条件的测试项(例如,基于标记 -m 的过滤就是在这里实现的)。
重新排序
改变测试项的执行顺序。
添加/修改参数化
动态地改变测试项的参数。
8. 收集完成:
Collection Phase 结束,Pytest 打印出收集到的测试项数量,然后进入 Execution Phase(执行阶段)。
这个流程展示了 Pytest 如何通过分层的 Collector 结构(Session -> Package/Directory -> Module -> Class)逐步深入,最终找到并组织所有的 Function 测试项。
最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】