夜雨聆风学习资料网

ARTICLE · 1289803

pytest 插件与工程化配置:从"能用"到"好用"

pytest 插件与工程化配置:从"能用"到"好用"

关注开源优测不迷路

大数据测试过程、策略及挑战

测试框架原理,构建成功的基石

在自动化测试工作之前,你应该知道的10条建议

在自动化测试中,重要的不是工具

关键技术点:
  • 插件安装:pip install pytest-NAME,装好自动发现,无需激活
  • pytest-xdist:-n auto/-n 4 并行,boxed 模式,looponfailing
  • pytest-cov:覆盖率,兼容分布式,--cov
  • pytest-instafail:测试进行时即报失败
  • pytest-timeout:超时控制
  • pytest-pep8/pytest-flakes:代码规范检查
  • pytest-html:生成 HTML 报告
  • 配置文件:[pytest] 段在 pytest.ini,addopts,testpaths,markers,python_files
  • pyproject.toml 的 [tool.pytest.ini_options]
  • -k 按名字筛选、-m 按标记筛选
  • 注册自定义标记:pytest.ini 的 markers= 或 pytest_configure 钩子
  • --strict-markers 严格模式
  • addopts 默认命令行选项
  • testpaths 限制搜索目录
  • 插件禁用:-p no:xxx
  • 插件生态 1300+ 外部插件
前几篇,我们把 pytest 的测试用例写得有模有样了:能发现、能 fixture、能参数化。但你可能慢慢意识到一个问题——这些测试跑起来,还不够"顺手"。
比如测试一多,几百上千个用例串行跑,慢得让人打瞌睡;跑完了想要个漂亮的报告给团队看,pytest 默认的输出又不那么直观;还有那些"跑一会就超时卡死"的用例,你想让它报错却不知道怎么设限。
这一篇,我们就来解决"好用"的问题。靠两样东西:配置和插件。一句话概括:配置让你不用每次都敲一大堆参数,插件让你想给 pytest 加什么功能就加什么功能。

一、先认识 pytest 的插件机制

先说插件是什么。pytest 本身是一个强大的框架,但很多实用功能(HTML 报告、并行执行、覆盖率统计、失败重试)它自己没做,而是留给"插件"来补。pytest 的插件生态非常庞大,光第三方插件就有 1300+ 个。
插件的安装和使用,比你想的还简单。pytest 官方文档说得很清楚:

告诉我怎么安装一个 pytest 第三方插件,比如 pytest-cov。装完之后需要激活它吗?

AI 会告诉你:
pip install pytest-cov
关键就在这——插件装好,pytest 会自动发现并集成它,不需要你手动激活。这是 pytest 设计得很爽的地方。装完直接用,比如 pytest --cov 就能统计覆盖率。
插件怎么"用"呢?三种方式:一是命令行参数(如 --html=report.html),二是配置文件(pytest.ini / pyproject.toml),三是作为 fixture 或 mark 用(如内置的 tmp_path、caplog)。
个别时候你想临时禁用某个插件,pytest 也支持:pytest -p no:cacheprovider,加个 no: 前缀就行。

二、三个"必装"插件:让 pytest 脱胎换骨

插件那么多,新手该先装哪几个?我给你选三个最值得的,也是几乎所有工程化项目都会用的。
第一个是 pytest-xdist——并行执行。测试一多,串行跑慢得揪心。pytest-xdist 能把测试分布到多个 CPU 核心并行跑,速度立竿见影。你可以在 CodeBuddy 或 Trae 里问 AI:

告诉我怎么安装 pytest-xdist,并说明如何用 4 个并行进程跑测试,以及 -n auto 是什么意思。

AI 会告诉你:
pip install pytest-xdist

用 4 个并行进程

pytest -n 4

自动用所有可用 CPU 核心

pytest -n auto
-n auto 会自动探测你机器的 CPU 核心数,把测试分发到这些并行 worker 上跑。对动辄上千用例的套件,这一步能把执行时间从"几十分钟"压到"几分钟"。
但这里有个重要的坑,你迟早会遇到:并行会暴露测试之间的"隐藏耦合"。有些测试单跑没问题,一并行就挂——因为它们共享了全局变量、临时文件、数据库状态。解决办法是让测试尽量无状态、互相独立,而不是关掉并行。这个后面写用例时会反复强调。
第二个是 pytest-cov——代码覆盖率。它能告诉你"你的测试到底覆盖了哪些代码行、哪些还没测到"。这是判断测试质量最直观的指标之一。让 AI 演示:

告诉我怎么安装 pytest-cov,并用它统计 src 目录的覆盖率,生成 HTML 覆盖率报告。

AI 会告诉你:
pip install pytest-cov

统计 src 目录的覆盖率

pytest --cov=src

生成 HTML 覆盖率报告

pytest --cov=src --cov-report=html

覆盖率低于 80% 就失败

pytest --cov=src --cov-fail-under=80
那行 --cov-fail-under=80 特别实用——它给测试设了一条"及格线",覆盖率掉到 80% 以下,CI 直接判失败,倒逼团队保持测试质量。
第三个是 pytest-html——漂亮的 HTML 报告。默认 pytest 的输出在终端里看够了,但要分享给非技术的领导、放进 CI 看板,HTML 报告直观得多。让 AI 演示:

告诉我怎么安装 pytest-html,并生成一个自带 CSS 样式的 HTML 测试报告。

AI 会告诉你:
pip install pytest-html
pytest --html=report.html --self-contained-html
那个 --self-contained-html 会把 CSS/JS 内嵌进 HTML,方便直接发给别人打开看。报告里通常包含通过/失败概览、每个用例的耗时、完整的错误回溯、环境信息,还能按结果筛选。
除了这三个,还有几个也值得记着:pytest-instafail(测试进行时就立刻报失败,不用等跑完)、pytest-timeout(给用例设超时,防止卡死挂起)、pytest-rerunfailures(失败自动重试,对付偶发的 flaky 测试)、pytest-mock(简化 mock)。这些用到时再逐个深入。

三、配置文件:把"常用参数"写死,别再反复敲

你可能已经发现了:pytest -n auto --cov=src --cov-report=html 这一串,每次跑都得敲,烦不烦?
pytest 允许你把这些"常用默认"写进配置文件,之后直接敲 pytest 就全带上了。配置文件可以是pytest.ini,也可以是pyproject.toml(现代项目更推荐,能跟项目元数据放一起)。
让 AI 帮你写一个 pytest.ini:

帮我写一个 pytest.ini 配置文件:1. 设置 addopts 为 "-ra -q"(显示更多汇总信息、安静输出);2. 设置 testpaths 为 "tests"(只搜索 tests 目录);3. 注册两个自定义标记:smoke 和 slow。加中文注释。

AI 会生成类似:

pytest.ini

[pytest]

默认命令行选项

addopts = -ra -q

只从 tests 目录搜索测试

testpaths = tests

注册自定义标记

markers =
smoke: 冒烟测试
slow: 慢速测试
几个关键配置项我给你解释一下:
addopts
:默认追加的命令行参数。上面 -ra 是"显示所有测试的汇总摘要",-q 是安静模式。这样你敲 pytest,实际等于敲了 pytest -ra -q。注意:如果命令行又传了冲突参数,命令行会覆盖配置里的(比如 -v 会盖过 -q)。
testpaths
:限定搜索目录。只搜 tests 目录,既加快收集速度,又避免误收项目里别处的测试文件。
markers
:注册自定义标记。这样用 @pytest.mark.smoke 就不会报"未知标记"警告。
如果你用 pyproject.toml,对应写法是 [tool.pytest.ini_options],格式略有不同,但配置项几乎一样。你可以让 AI 帮你把 pytest.ini 转成 pyproject.toml 版本对比着看。

四、精准筛选:用 -k 和 -m 只跑想跑的

工程化的另一个实用能力,是精确挑选要跑的测试。pytest 给了两个利器:-k按名字筛选、-m按标记筛选。
-k按名字匹配。pytest 官方文档说,-k 用表达式对测试名做子串匹配,而且大小写不敏感。让 AI 演示:

告诉我如何用 pytest -k 只运行测试名中包含 "http" 的测试,以及如何排除包含 "slow" 的测试。

AI 会告诉你:

只跑名字含 http 的

pytest -v -k http

排除名字含 slow 的

pytest -k "not slow"

组合条件

pytest -k "http and not slow"
-k 的表达式支持 and、or、not 和括号。而且 -k 不光匹配函数名,还匹配文件名、类名、标记名。调试某个模块时,pytest -k user 一下就能精准定位相关测试,比全量跑省太多时间。
-m按标记筛选。这要和前面在配置文件里注册的 markers 配合。你可以在测试上用 @pytest.mark.smoke 打个标记,然后只跑冒烟测试。让 AI 演示:

写一个 pytest 测试,用 @pytest.mark.smoke 标记它是冒烟测试。然后告诉我怎么用 -m 只跑冒烟测试。

AI 会生成:
import pytest
@pytest.mark.smoke
def test_login_success():
assert login("alice", "123456") == "通过"
运行:

只跑标记为 smoke 的测试

pytest -m smoke

跑除了 slow 之外的所有测试

pytest -m "not slow"
-m smoke 会只跑那些标了 @pytest.mark.smoke 的测试。这在 CI 里特别常用——比如每次提交只跑 smoke,全量回归单独安排,既快又准。

五、标记进阶:让测试"带标签"又"带规则"

前面我们用了 @pytest.mark.smoke,这其实是 pytest标记(mark)体系的一部分。除了自定义标记,pytest 还内置了好几个常用的:
@pytest.mark.skip(reason=...)
:无条件跳过某个测试。
@pytest.mark.skipif(condition, reason=...)
:满足条件才跳过。
@pytest.mark.xfail
:标记"预期失败"。
@pytest.mark.parametrize
:上一篇讲过的参数化,本质也是标记。
让 AI 演示 skipif 的用法:

写一个 pytest 测试,用 @pytest.mark.skipif 标记:当 sys.platform 等于 "win32" 时跳过这个测试,并给出理由 "Windows 暂不支持"。

AI 会生成:
import sys
import pytest
@pytest.mark.skipif(sys.platform == "win32", reason="Windows 暂不支持")
def test_linux_only_feature():
assert check_linux_feature() == True
这样在 Windows 上跑,这个测试会被跳过(显示为 s),而不是失败。
还有一个重要的工程化开关叫--strict-markers。让 AI 解释一下:

pytest 的 --strict-markers 选项有什么用?为什么推荐在项目里开启它?

AI 会告诉你:开启 --strict-markers 后,如果你用了一个没在配置文件里注册的标记,pytest 会直接报错。这能防止团队里出现拼错标记名、滥用未定义标记的低级错误,让测试套件更"诚实"。建议在 addopts 里加上它。

六、把砖块砌起来:一份"开箱即用"的工程化配置

现在把这一篇讲的都收拢起来,让 AI 帮你配一份完整的工程化配置。你可以这样跟 CodeBuddy 或 Trae 说:

帮我把一个测试项目配置成工程化:1. 用 pyproject.toml 配置 pytest:testpaths 指向 tests,addopts 设为 [-v, --strict-markers, --tb=short, --cov=src, --cov-report=term-missing, --cov-fail-under=80];2. 注册标记 smoke 和 integration;3. 用一个 conftest.py 放一个全局的 api_client fixture(返回一个模拟客户端对象)。加中文注释。

AI 会生成类似:

pyproject.toml

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"-v",
"--strict-markers",
"--tb=short",
"--cov=src",
"--cov-report=term-missing",
"--cov-fail-under=80",
]
markers = [
"smoke: 冒烟测试",
"integration: 集成测试",
]

conftest.py

import pytest
@pytest.fixture
def api_client():
return MockApiClient()

一个模拟的客户端

你这次要做的事,不是看它跑没跑对,而是通读一遍,问自己几个问题:
addopts
里的参数,是不是覆盖了"详细输出、严格标记、短回溯、覆盖率统计、覆盖率门槛"这几件事?
--cov-fail-under=80
是不是设定了"覆盖率低于 80% 就失败"的及格线?
标记 smoke 和 integration 是不是注册了,配 --strict-markers 不会误报?
如果哪里不满意,就基于上一轮继续让 AI 改。比如:

再加一个 --cov-report=html,并把覆盖率门槛改成 85。

到这一步,你就拥有一份"开箱即用"的工程化配置了。以后团队里任何人 clone 这个项目,装好依赖敲 pytest,就会自动跑测试、出覆盖率、报 HTML 报告、守住及格线——一套流程全自动。
顺带说一句,pytest 的官方手册(也是我前面很多细节的来源)里反复强调的一个理念值得你记住:好的测试套件要"简单的事保持简单,复杂的事足够强大"——fixture、参数化、标记、插件这一整套,就是让你在保持简单的同时,能扩展到最大的测试套件。

小结

这一篇我们把 pytest 从"能用"调教成了"好用"。总结一下:
插件机制
:pip install pytest-NAME 装完自动生效,不用激活;
三个必装插件
:pytest-xdist(并行)、pytest-cov(覆盖率)、pytest-html(报告);
配置文件
:pytest.ini 或 pyproject.toml 的 [pytest]/[tool.pytest.ini_options],用 addopts、testpaths、markers 固化默认;
精准筛选
:-k 按名字、-m 按标记;
标记体系
:skip/skipif/xfail/parametrize + --strict-markers 严格模式。
这一篇的配置代码,依旧是靠和 CodeBuddy、Trae 对话生成的。你做的,是想清楚"这个项目要哪些默认行为、要哪些标记",然后通读 AI 生成的配置、核对每一项。
留道思考题:

打开你的 Trae 或 CodeBuddy,让 AI 帮你写一份 pyproject.toml 的 pytest 配置:testpaths 指向 tests,addopts 包含并行执行(-n auto)、覆盖率(--cov=src --cov-fail-under=80)、HTML 报告。生成后通读一遍,确认每个参数都对应一个目的,再跑一下你的测试看看效果。

下一篇,我们进入 Web 自动化的世界——Selenium WebDriver 全解析,看看怎么用 Python 控制真实浏览器去做端到端测试。
我们下篇见。

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料