、testr 常用命令
2026/7/19 5:29:29 网站建设 项目流程

初始化测试仓库(项目根目录)

testr init

运行全部测试

testr run

运行指定测试(支持正则)

testr run mypackage.tests.test_foo

只跑上次失败的测试(failing-first,加速回归)

testr run --failing

查看上次运行结果

testr last

查看 N 次运行中最慢的测试

testr slowest

列出上次失败的测试

testr failing

在上次失败的基础上再次跑

testr run --subunit | subunit-filter --no-success | subunit2pyunit

把上次的 subunit 流转成 HTML 报告

testr last --subunit | subunit2html output.html
六、并行执行机制
testr 的并行能力是其最大价值之一。流程:

  1. testr 调用 test_list_command 获取全部 test ID
  2. 按 group_regex 把测试分成若干「组」(同组测试不会拆到不同 worker,避免共享 fixture 冲突)
  3. 启动 N 个 worker 进程(默认 = CPU 核数)
  4. 每个 worker 拿到自己的测试子集,通过 test_command 执行
  5. 各 worker 的 subunit 流汇入 testr 的总流
  6. testr 实时把汇总流写入 .testr/last 和终端
    配置并发数:

通过环境变量

TESTRUN_CONCURRENCY=8 testr run

或在 .testr.conf 中指定

[DEFAULT]
test_concurrency=8
注意:并行要求测试之间无共享状态/全局 fixture。如果用 setUpClass/setUpModule 做数据库初始化,多 worker
会各自跑一次,可能造成连接数爆炸。

七、subunit 流的处理
subunit 是 testr 体系的「血液」。常用管道命令:

把上次结果中失败的测试抽出来再跑

testr last --subunit | subunit-filter --no-success | subunit-run

实时把 subunit 流转换成人类可读输出

testr run --subunit | subunit2pyunit

转 HTML

testr run --subunit | subunit2html report.html

转 JUnit XML(兼容 CI)

testr run --subunit | subunit2junitxml junit.xml

过滤出只跑某个 package

testr run --subunit | subunit-filter --name-pattern ‘mypackage.tests.test_db’ | subunit-run
这是 testr 区别于 pytest 的关键:测试结果是一段可流动的数据,不是固定的报告文件。你可以任意接管道处理。

八、最小可运行示例
8.1 项目结构
myproject/
├── myproject/
│ ├──init.py
│ └── foo.py
├── myproject/tests/
│ ├──init.py
│ ├── test_foo.py
├── tox.ini
├── .testr.conf
├── requirements.txt
└── test-requirements.txt
8.2 test-requirements.txt
testrepository
subunit
fixtures
testtools
8.3 .testr.conf
[DEFAULT]
test_command = python -m subunit.run discover -t . myproject/tests $LISTOPT
test_list_command = python -m subunit.run discover -t . myproject/tests --list
8.4 tox.ini
│ Step 5 : testr 读取 .testr/config 获取 test_command │
│ 读取 .testr/history 准备 failing-first 调度 │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Step 6 : testr 调用 test_list_command 列出全部测试 ID │
│ 按 group_regex 切分,分发给 N 个并行 worker │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Step 7 : 每个 worker 执行: │
│ python -m subunit.run discover -t . $TESTS_DIR <test_ids> │
│ 输出 subunit 流到 stdout │
└─────────────────────────────────────────────────────┬───────┘

┌───────────────────────────────────────────────┘
│ (多个 worker 的 subunit 流汇入)

┌─────────────────────────────────────────────────────────────┐
│ Step 8 : testr 把 subunit 流 tee 到: │
│ - .testr/last (上次完整流) │
│ - .testr/history (累积历史,供下次调度) │
│ - 实时渲染到终端 (subunit2py 或 subunit2html) │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Step 9 : testr 统计 pass/fail/skip,以 exit code 返回 │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Step 10 : tox 接收到 exit code, │
│ 非 0 则标记 env 失败,汇总到最终结果 │
└─────────────────────────────────────────────────────────────┘
九、failing-first:核心加速技巧
testr 的 .testr/history 记录了每个测试最近的通过/失败状态。下次跑时:

testr run --failing
会优先调度上次失败的测试,先跑、先报错。如果开发者在改动的就是那部分代码,几秒就能看到红;如果之前的失败已经修好,剩余测试再继续跑。

这相当于把「全量回归」的反馈时间从「全部跑完才看到失败」变成「失败先暴露」,在大型项目里收益巨大。

十、常见坑
坑 1:testr init 未执行
第一次跑 testr run 会报 No testrepository found。

解决

testr init
tox.ini 里可以加一行自动初始化:

commands =
testr init
testr run {posargs}
坑 2:并行下 fixture 冲突
例如 setUpClass 里建表,多个 worker 同时建,数据库报错。

解决:

把不可并行的 fixture 改成模块级单例 + 锁
或降低 test_concurrency=1 退回串行
或用 group_regex 把相关测试归到同一 worker
坑 3:subunit.run 找不到测试
subunit.run discover 默认从当前目录发现,如果 TESTS_DIR 没设对,会跑空。

[DEFAULT]
test_command = python -m subunit.run discover -t . myproject/tests $LISTOPT

^^^^^^^^^^^^^^^^^ 明确指定目录

坑 4:覆盖率和 testr 一起跑
不能直接 coverage run testr run,因为 testr 会 fork 子进程,coverage 抓不到。

正确做法:

[testenv:cover]
setenv = PYTHON=coverage run --source myproject -m testr run
commands =
coverage erase
{env:PYTHON}
coverage report
把 coverage 作为 python 解释器前缀 注入,让每个 worker 都在 coverage 下跑。

坑 5:Windows 兼容性
testr 在 Windows 上偶发问题(并行进程、路径分隔符)。如果必须在 Windows 跑,建议:

[testenv]
setenv = TESTRUN_CONCURRENCY=1
退回串行,稳定性优先。

十一、和 pytest 的对比
维度 tox + testr pytest + pytest-xdist
环境隔离 tox 原生支持 需配合 tox 或 nox
并行 testr 调度,基于 subunit pytest-xdist,worker 进程
结果持久化 .testr/history,可 failing-first 需 pytest-cache 或 --lf
流式协议 subunit,可流式管道处理 原生流式但不可管道组合
生态 OpenStack 系,偏传统 现代主流
配置复杂度 高(tox.ini + .testr.conf) 低(pyproject.toml 一处)
学习曲线 陡 平
建议:

老项目、OpenStack 系、需要 subunit 流生态 → 继续 tox + testr
新项目、Python 3.10+、追求简洁 → tox + pytest 或 nox + pytest
十二、最佳实践清单
.testr/ 加入 .gitignore,但 .testr.conf 提交
CI 中先 testr init 再 tox,避免空仓库报错
本地用 --failing 做快速回归,CI 用全量跑
group_regex 一定要设,否则并行下共享 fixture 测试会炸
覆盖率和并行分开跑,coverage 走单独 env
subunit2html 产物归档,方便回溯历史失败
不要在 test_command 里写死 worker 数,用环境变量注入,方便 CI 调
定期清理 .testr/history,长期累积会变慢
CI 用 testr last --subunit | subunit2junitxml 生成 JUnit 报告,Jenkins/GitLab 原生解析
大型项目把单元/集成测拆成不同 env,testr 只管单测,集成测用别的工具
十三、速查表

项目初始化

testr init

全量跑

tox -e py311

只跑失败

tox -e py311 – --failing

跑指定测试

tox -e py311 – mypackage.tests.test_foo.TestBar.test_baz

看上次结果

testr last

看最慢的 20 个

testr slowest

转 HTML

testr last --subunit | subunit2html report.html

转 JUnit XML

testr last --subunit | subunit2junitxml junit.xml

重置仓库

rm -rf .testr && testr init
十四、结语
tox + testr 的组合,核心是三层解耦:

工具 优势
tox 隔离测试环境,避免污染系统 Python;–sitepackages 复用预装包加速
testr 支持测试并行(按 group_regex 分组),自动重跑失败用例,subunit 流归档可复现
subunit 与语言无关的标准测试流格式,能被多种工具(trace/junitxml/html)二次加工

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询