登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  软件教程

CTest 怎么只重跑上次失败的测试

来源:17golang原创

时间:2026-10-13 06:55:22 459浏览 收藏

CTest 支持直接重跑上一轮失败的测试:在已经执行过完整测试的构建目录中运行 ctest --rerun-failed 即可。它会把测试集合缩小到上次失败的项目,不需要把已经通过的用例再跑一遍;如果这次失败输出需要展开,再附加 --output-on-failure。

官方地址:https://cmake.org/cmake/help/latest/manual/ctest.1.html

最稳妥的使用顺序是:进入正确的构建目录,先完整运行一次 CTest,确认出现失败后,再执行 ctest --rerun-failed --output-on-failure。不要把它当作正则筛选开关,因为 CTest 会忽略其他用于改变测试集合的选项。

先把测试入口和构建目录对上

CTest 读取的是构建树里的 CTestTestfile.cmake。因此“只重跑失败测试”的第一步不是勾选某个选项,而是确认测试面板使用的构建目录,和上一次完整测试写入失败记录的目录相同。

# 进入 CMake 生成的构建目录,不要在源码目录凭空执行
cd build

# 查看当前目录是否包含 CTest 的测试入口文件
test -f CTestTestfile.cmake && echo "测试入口已找到"

# 先列出测试数量,确认面板和命令行指向的是同一棵构建树
ctest --show-only=human

如果你在 IDE 或构建工具面板里操作,先打开“测试 / Tests”区域,再确认“构建目录 / Build directory”字段。图中的界面是帮助定位字段的原创示意,不代表真实 CMake 或某个 IDE 的截图。

原创软件界面说明图:在 CTest 测试面板中定位构建目录和失败记录入口
图1:在测试面板中确认构建目录、完整测试入口和失败记录状态;这是原创操作示意图,不是实际软件截图。
  1. 在左侧项目区域打开“测试 / Tests”。
  2. 在构建目录字段确认当前目录包含测试生成文件。
  3. 先选择“运行全部测试 / Run all tests”,让 CTest 产生本轮结果。
  4. 看到失败计数后,再把运行模式切换为“仅重跑失败 / Rerun failed”。

先完整运行一次,让 CTest 记住失败集合

--rerun-failed 不是凭空发现失败用例,它依赖此前一次 CTest 运行留下的失败结果。第一次排查时先运行完整集合,并用 --output-on-failure 把失败测试自己的输出显示出来。

# 第一次运行完整测试集,并在失败时直接展开测试程序输出
ctest --output-on-failure

# 用退出码判断整轮是否有失败;失败时保留终端日志供下一步定位
test "$?" -eq 0 && echo "全部通过" || echo "存在失败测试,请执行仅失败重跑"

这里的完整运行承担两个作用:给出当前测试总结果,同时留下下一次 --rerun-failed 需要的失败集合。若所有测试都通过,就没有“需要缩小”的失败集合,应该把这一轮视为正常验收,而不是强行重跑。

用一个命令只重跑上次失败的测试

确认上一轮确实有失败后,直接在同一个构建目录执行下面的命令:

# 只重跑上一轮失败的测试,并保留失败测试的详细输出
ctest --rerun-failed --output-on-failure

这条命令的重点是“失败集合”,而不是测试名称。上一轮已经通过的测试不会因为这次重跑而重新执行,特别适合先修一个用例、再快速确认修复是否有效的循环。

CTest 官方说明还特别强调,指定 --rerun-failed 后,-R、-E、-L、-I 等用于改变测试列表的选项会被忽略。本文不把这些筛选正则和失败记录混用:需要按名称筛选时,应回到单独的测试选择命令。

原创软件界面说明图:CTest 面板显示仅重跑失败测试后的结果状态
图2:仅失败重跑后的结果状态,展示失败集合、重跑计数和输出入口;这是原创结果示意图,不是实际软件截图。

把输出、退出码和下一轮对象分开看

排查时容易把“有输出”和“命令失败”混成一件事。--output-on-failure 只负责在测试失败时显示测试程序输出,不能改变 CTest 的选择范围。只要至少一个测试失败,CTest 的退出码就是非零;全部通过时退出码为 0。

# 将结果保存到日志文件,便于在面板外复查本轮重跑内容
ctest --rerun-failed --output-on-failure --output-log rerun-failed.log

# shell 中用最后一条命令的退出码决定流水线是否继续
if [ "$?" -eq 0 ]; then
  echo "失败集合已经全部通过"
else
  echo "仍有失败项,保留日志并继续修复"
fi

如果修复后仍有失败,下一次调用会继续围绕最近失败的集合工作;如果本轮全部通过,就可以回到完整测试命令,确认没有遗漏此前没有执行的测试。

三个最容易误判的状态

看到的状态实际含义下一步
第一次直接执行 --rerun-failed没有可用的失败记录,可能不会执行你期待的测试先在同一构建目录运行完整测试
上一轮全部通过后仍执行重跑没有新的失败项可供缩小集合回到完整测试或结束本轮验收
重跑数量和预期不一致当前目录与之前运行的构建目录不一致,或测试生成文件已经更新核对测试面板的构建目录和 CTestTestfile.cmake

尤其要注意构建配置。Debug 和 Release 可能使用不同的构建目录,失败记录也不应跨目录猜测。把“记录属于哪棵构建树”先确认清楚,通常比不断添加命令行参数更有效。

在测试面板里固定一条可复用的操作路径

如果团队主要通过软件界面运行测试,可以把操作固定成一条短路径:先选择构建目录,再运行全部测试,失败后选择仅失败重跑,最后打开失败输出并查看结果日志。界面中的字段名称应服务于这四个动作,不要把“按名称筛选”和“重跑失败集合”放在同一个开关里。

  1. 打开“测试 / Tests”面板,选择本次构建配置。
  2. 点击“运行全部 / Run all”,等待失败计数落定。
  3. 点击“仅失败 / Rerun failed”,必要时打开“失败输出 / Output on failure”。
  4. 看到失败计数为零后,再决定结束验收还是回到完整测试。

常见问题

为什么第一次运行 ctest --rerun-failed 没有按预期执行?

它需要此前一次测试运行产生的失败集合。先在目标构建目录执行完整测试,再执行仅失败重跑。

--rerun-failed 能不能和 -R 一起限制测试名称?

不建议这样理解。官方文档说明,启用 --rerun-failed 时,其他用于修改测试列表的选项会被忽略。按名称筛选应单独使用测试选择命令。

重跑后全部通过,下一次还要继续执行 --rerun-failed 吗?

如果没有新的失败,通常没有必要继续重复重跑。回到完整测试做一次整体确认,或者结束当前修复循环。

最后只核对这四项

  • 当前命令执行在正确的构建目录,能找到 CTestTestfile.cmake。
  • 已经先运行过一次完整测试,并确实产生了失败集合。
  • 重跑命令使用 ctest --rerun-failed --output-on-failure,没有把它误当成正则筛选。
  • 根据新的退出码和失败计数决定继续修复、回到完整测试,还是结束验收。
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>