pytest-picked 是基于 Git 暂存区变更,通过静态 import 路径匹配反向定位并仅运行相关测试文件的 pytest 插件;它依赖 git add 后的 staged 文件,不分析调用链或 diff 内容,仅匹配 import 关系,支持 --picked-root、--picked-test-root 等参数适配复杂项目结构。

pytest-picked 是什么,它真能只跑暂存区的测试?
能,但有前提:它不是“自动识别业务逻辑影响范围”,而是基于 Git 文件变更路径,反向查找哪些 test_*.py 或 *_test.py 文件 import 了被修改的源码模块——再只运行这些测试文件。它不分析函数调用链,也不看 diff 内容是否真影响行为,只做静态 import 路径匹配。
这意味着:
• 如果你改了 utils.py,但测试文件是通过 from mypkg import utils 导入的,pytest-picked 能找到对应测试;
• 但如果测试里用了 eval("import utils") 或动态导入,它就失效;
• 如果你只改了测试文件本身(比如修复一个断言),它也会把该测试文件纳入运行范围。
安装和基础用法:别漏掉 git add 这一步
pytest-picked 的核心逻辑依赖 git diff --cached(即暂存区 diff),所以必须先 git add,否则它找不到任何改动,直接退出或报错 No files to test。
- 安装:
pip install pytest-picked - 确保已暂存修改:
git add mymodule.py tests/test_mymodule.py - 运行:
pytest --picked
它会输出类似:Running tests related to staged changes...collected 3 items / 12 deselected / 3 selected
然后只执行那 3 个被选中的测试文件。
立即学习“Python免费学习笔记(深入)”;
常见失败场景:为什么它有时“没反应”或“跑全量”?
最常踩的坑不是插件坏了,而是环境或 Git 状态不符合预期:
-
git status显示 “nothing to commit, working tree clean” —— 说明没git add,--picked找不到 staged 文件,退化为普通pytest行为 - 修改的源码文件没被任何测试 import(比如新写的工具函数还没写测试),
pytest-picked就不会选中任何测试,输出0 tests collected - 项目结构复杂,比如测试和源码不在标准目录(如
src/+tests/),默认配置无法正确映射路径 —— 需要配--picked-root或--picked-test-root - 用了非标准 import 别名(如
import mypkg.utils as u),不影响匹配;但若源码路径和 import 路径不一致(如源码在lib/utils.py,却用from mypkg import utils),需通过--picked-mapping手动声明映射关系
进阶控制:跳过某些文件、指定根目录、避免误伤
默认行为足够简单项目用,但中大型项目常需要微调:
- 指定源码根目录(当项目用
src/结构):pytest --picked --picked-root=src - 显式声明测试根目录(避免扫描错误路径):
pytest --picked --picked-test-root=tests - 忽略某些路径(比如不希望因改了
migrations/就触发测试):pytest --picked --picked-ignore=migrations/** - 强制包含某测试文件(调试时绕过 import 分析):
pytest --picked --picked-include=tests/test_edge_case.py
注意:--picked-ignore 和 --picked-include 接收 glob 模式,不是正则;路径匹配基于文件系统实际路径,不是 Git 相对路径。
真正容易被忽略的是:它只看 staged 文件,不看 unstaged 或 untracked;如果本地改完忘了 git add,或者 CI 流水线里 checkout 后没做 git add(比如只 diff HEAD~1),结果就是“啥都不跑”。


















