📝 面试求职: 「面试试题小程序」 ,内容涵盖 测试基础、Linux操作系统、MySQL数据库、Web功能测试、接口测试、APPium移动端测试、Python知识、Selenium自动化测试相关、性能测试、性能测试、计算机网络知识、Jmeter、HR面试,命中率杠杠的。(大家刷起来…)
📝 职场经验干货:
上篇文章为大家讲解了什么是测试用例发现、Pytest 的默认用例发现规则、Pytest 用例发现的内部流程。
今天,继续带大家深入聊聊我们日常工作中广泛使用的 Python 测试框架——Pytest的定制化测试发现规则、常见问题与排查技巧、总结与最佳实践。
文章导览
1. 什么是测试用例发现(Test Discovery)?
2. Pytest 的默认用例发现规则
3. Pytest 用例发现的内部流程:深入 Collection Phase(收集阶段)
4. 定制化你的测试发现规则
5. 常见问题与排查技巧(Troubleshooting)
6. 总结与最佳实践
7. 结语
定制化你的测试发现规则
虽然默认规则在大多数情况下够用,但有时我们需要根据项目特点调整发现行为。
Pytest 提供了多种方式进行定制:
1. 通过配置文件
这是最常用也推荐的方式。
在项目根目录下的 pytest.ini 文件
(或 pyproject.toml 中的 [tool.pytest.ini_options] 表,或 setup.cfg 中的 [tool:pytest] 段)中,你可以修改以下选项:
python_files
Glob 文件模式,用于匹配测试文件。可以设置多个模式,用空格分隔。
[pytest]
python_files = test_.py check_.py _spec.py
python_classes
Glob 类名模式,用于匹配测试类。可以设置多个模式。
注意,Test 前缀是默认包含的,除非你完全覆盖它。通常是添加模式,例如让 Check 开头的类也被识别。
[pytest]
python_classes = Test Check Suite
python_functions
Glob 函数/方法名模式,用于匹配测试函数。可以设置多个模式。
[pytest]
python_functions = test_ check_ scenario_
norecursedirs
空格分隔的目录名模式列表,指定哪些目录在递归查找时应该被忽略。
[pytest]
norecursedirs = .git . venv dist build tmp docs
2. 通过命令行选项
--ignore=path
忽略指定的路径(文件或目录)。可以多次使用。
pytest --ignore=tests/legacy --ignore=tests/integration/test_slow.py
--ignore-glob=pattern
忽略匹配 glob 模式的路径。可以多次使用。
pytest --ignore-glob='_vendor/'
--collect-only 或 --co
只执行收集阶段,不执行测试。用于检查哪些测试会被发现,非常适合调试发现问题。配合 -q (quiet) 或 -v (verbose) 使用效果更佳。
pytest --collect-only -q # 安静模式,只列出 Node ID
pytest --collect-only -v # 详细模式,显示收集过程
3. 通过 conftest.py 文件
conftest.py 是 Pytest 的本地插件文件,它允许你在特定目录下定制 Pytest 行为,包括测试发现。
collect_ignore 列表
在 conftest.py 文件中定义一个名为 collect_ignore 的列表,包含相对于该 conftest.py 所在目录的子目录名或文件名字符串,这些路径将被忽略。
# tests/conftest.py
collect_ignore = ["helpers", "fixtures/data.py"] # 忽略 tests/helpers/ 目录和 tests/fixtures/data.py 文件
collect_ignore_glob 列表 (Pytest 6.0+)
类似于--ignore-glob,在 conftest.py 中定义 collect_ignore_glob 列表,包含 glob 模式。
# tests/conftest.py
collect_ignore_glob = ["_integration.py"] # 忽略所有以 _integration.py 结尾的文件
注意:
conftest.py 中的 collect_ignore
和 collect_ignore_glob 只影响其所在目录及其子目录的收集行为。
实现 Collection Hooks
这是最高级的定制方式。你可以在 conftest.py 或安装的插件中实现 Pytest 的 Collection Hooks(收集钩子)来完全控制发现逻辑。
-
pytest_collect_file(path, parent):
决定是否要为一个给定的文件路径 path 创建一个 Module Collector。你可以返回一个自定义的 Collector 节点,或者返回 None 来阻止默认的收集行为。这对于收集非 Python 文件中的测试很有用。
-
pytest_pycollect_makemodule(path, parent):
定制 Module 节点的创建。
-
pytest_pycollect_makeitem(collector, name, obj):
当 Module 或 Class Collector 发现一个潜在的测试项(函数或方法 obj,名为 name)时调用。
你可以返回一个自定义的测试项节点、多个节点(例如用于生成测试),或者返回 None 来阻止该项被收集。
-
pytest_collection_modifyitems(session, config, items):
如前所述,在收集完成后修改 items 列表。
使用 Collection Hooks 需要对 Pytest 的内部结构有较深的理解,通常用于插件开发或非常特殊的项目需求。
常见问题与排查技巧
(Troubleshooting)
理解了原理,当遇到问题时就能更有条理地排查:
1. 测试用例没有被发现:
-
检查命名:
是否符合 python_files, python_classes, python_functions 的模式?(最常见)
-
检查 __init__:
测试类是否包含了 __init__ 方法?
-
检查目录/文件是否被忽略:
是否在 norecursedirs 配置中?
是否被 --ignore 或 conftest.py 中的
collect_ignore / collect_ignore_glob 排除?
-
检查语法错误:
文件是否能被 Python 正常导入?
Pytest 在导入失败时会跳过该文件。
运行 python -m py_compile path/to/your/test_file.py 检查。
-
使用 pytest --collect-only -v:
这是你的首选调试工具!它会显示 Pytest 尝试收集的每个文件和目录,以及为什么某些项被跳过或收集。仔细阅读其输出。
-
检查 conftest.py:
是否有 conftest.py 中的钩子意外地阻止了收集?
2. 不希望执行的函数/类被当作测试执行了:
-
检查命名:
是否意外地匹配了测试命名模式?(例如,一个辅助函数名为 test_helper())
-
调整命名规则:
如果项目中有大量非测试代码遵循了默认模式,考虑在 pytest.ini 中使用更精确的模式,例如 python_functions = test_ test_scenario_,避免过于宽泛的模式。
-
使用 _ 前缀:
Python 约定,以下划线 _ 开头的函数或类通常表示内部使用,Pytest 默认不会收集它们。可以将辅助函数命名为 _helper_function()。
-
使用 pytest.mark.skip
或 pytest.mark.skipif:
如果只是临时不想执行某个测试,或者在特定条件下跳过,使用标记是更好的方式。
3. __init__.py 文件在测试目录中的影响:
-
在测试根目录或子目录中放置 __init__.py 文件会将其标记为 Python 包。这对于使用相对导入组织测试代码或 Fixture 是有用的。
-
通常,它不会影响 Pytest 的文件和目录发现本身(Pytest 仍然会递归进入),但它会影响 Python 的模块导入行为。
-
再次强调,测试类内部的 __init__ 方法会导致该类不被 Pytest 收集。
4. 收集阶段性能问题:
在非常大的项目中,如果收集阶段花费时间过长:
-
确保 norecursedirs 配置包含了所有不需要检查的大型目录(如 node_modules, build 输出等)。
-
检查是否有低效的 Collection Hooks。
-
考虑拆分测试项目或更精细地指定要运行的测试子集。
-
使用 pytest --collect-only --durations=0 查看收集各个文件的时间。
总结与最佳实践
Pytest 的用例发现机制是其易用性和强大功能的基石。通过理解其默认规则、内部收集流程以及各种定制化手段,我们可以:
-
高效组织测试:
遵循约定,让 Pytest 自动完成繁琐的查找工作。
-
灵活适应项目:
通过配置或钩子,让 Pytest 适应特殊的项目结构或测试类型。
-
快速定位问题:
当发现行为不符合预期时,能有针对性地排查命名、配置或 conftest.py。
几点最佳实践建议:
1. 优先遵循默认约定:
这是最简单、最通用、最易于团队协作的方式。
2. 保持清晰的目录结构:
例如,将所有测试放在一个 tests/ 目录下,按功能或模块划分小子目录。
3. 谨慎使用 __init__:
避免在测试类中使用 __init__ 方法,优先使用 Fixture 进行设置和拆卸。测试目录中的 __init__.py 按需使用。
4. 配置文件优于钩子:
对于常见的定制需求(如修改命名模式、忽略路径),优先使用 pytest.ini 等配置文件,它们更直观易懂。仅在需要深度定制或实现插件时才使用 Collection Hooks。
5. 善用 --collect-only:
它是你调试发现问题的得力助手。
结语
通过本文的学习,相信你已经掌握了 Pytest 的用例发现原理,并透析Pytest测试框架内部运作。
希望这本文能帮助你更熟练地驾驭 Pytest,编写出更健壮、更易于维护的自动化测试。
最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】


被折叠的 条评论
为什么被折叠?



