掌握了它,你就掌握了 Pytest 的核心!测试效率飙升!

📝 面试求职: 「面试试题小程序」 ,内容涵盖 测试基础、Linux操作系统、MySQL数据库、Web功能测试、接口测试、APPium移动端测试、Python知识、Selenium自动化测试相关、性能测试、性能测试、计算机网络知识、Jmeter、HR面试,命中率杠杠的。(大家刷起来…)

📝 职场经验干货:

软件测试工程师简历上如何编写个人信息(一周8个面试)

软件测试工程师简历上如何编写专业技能(一周8个面试)

软件测试工程师简历上如何编写项目经验(一周8个面试)

软件测试工程师简历上如何编写个人荣誉(一周8个面试)

软件测试行情分享(这些都不了解就别贸然冲了.)

软件测试面试重点,搞清楚这些轻松拿到年薪30W+

软件测试面试刷题小程序免费使用(永久使用)


今天,我想和大家深入聊聊我们日常工作中广泛使用的 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%免费】

​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值