其他
当 Tuist 中测试被标记为 flaky 时…
适用于已接入 Tuist test insights 的项目,根据 flaky 测试指标、运行历史和失败信息定位并修复不稳定测试。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
当 Tuist 中测试被标记为 flak特定
解决思路
- Quick Start:收到 Tuist test case URL 或 identifier 后,运行 `tuist test case show <id-or-identifier> --json` 获取该测试的可靠性指标。
- Quick Start:运行 `tuist test case run list Module/Suite/TestCase --flaky --json` 查看 flaky run 模式。
- Quick Start:对失败的 flaky run 运行 `tuist test case run show <test-case-run-id> --json`,获取 failure messages 和 file paths。
- Quick Start:读取所报告路径和行号处的测试源码,识别 flaky 模式并进行修复。
- Quick Start:多次运行测试,确认其能稳定通过。
- Quick Start:如果没有提供具体测试,从 Discovery 步骤开始。
- Discovery:当未提供具体测试用例时,运行 `tuist test case list --flaky --json --page-size 50` 查找项目中所有当前被标记为 flaky 的测试。
- Discovery:使用返回字段 `module.name`、`suite.name`、`name` 定位测试标识;用 `avg_duration` 优先修快的单元测试;用 `is_quarantined` 判断测试是否已被隔离。
- Triage:按 suite 对测试分组;同一 suite 中多个 flaky 测试通常共享根因。
- Triage:检查失败是否共享 `test_run_id`;同一次运行中一起失败的测试可能是被进程崩溃杀死,而不是单个测试 bug。
- Triage:查看 failure messages 并分类为测试逻辑 bug 与基础设施问题,例如 network errors、server 502s、retry 冲突。
- Investigation:获取 test case metrics 时,可以传 UUID 或 `Module/Suite/TestCase` 标识,运行 `tuist test case show <id> --json` 或 `tuist test case show Module/Suite/TestCase --json`。
- Investigation:查看关键指标 `reliability_rate`、`flakiness_rate`、`total_runs`、`failed_runs`、`last_status`。
- Investigation:查看 flaky run history 时运行 `tuist test case run list Module/Suite/TestCase --flaky --json`;标识格式为 `ModuleName/SuiteName/TestCaseName`,没有 suite 时为 `ModuleName/TestCaseName`;该命令只返回被检测为 flaky 的运行。
- Investigation:查看完整运行历史时运行 `tuist test case run list Module/Suite/TestCase --json --page-size 20`。
- Investigation:在完整运行历史中寻找模式:是否只在特定分支失败、是否只在 CI 上失败(`is_ci: true`)还是本地也失败、失败是否聚集在特定 commit 附近。
- Investigation:获取 failure details 时运行 `tuist test case run show <test-case-run-id> --json`。
- Investigation:解读 failure details 字段:`failures[].message`、`failures[].path`、`failures[].line_number`、`failures[].issue_type`、`repetitions`、`test_run_id`、`crash_report`;`crash_report` 包含 `exception_type`、`signal`、`exception_subtype`、`triggered_thread_frames`。
- Code Analysis:打开 `failures[0].path` 指向的文件,并跳到 `failures[0].line_number`。
- Code Analysis:阅读完整测试函数及其 setup/teardown。
- Code Analysis:判断该测试属于下面哪个常见 flaky 模式。
- Code Analysis:检查该测试是否与同一 suite 中其他测试共享状态。
- Pattern:如果测试在 async 操作完成前检查结果,属于 Missing waits;修复方式是使用 `await`、带 timeout 的 expectations 或 polling。
- Pattern:如果多个并发操作访问共享状态,属于 Race conditions;修复方式是同步访问或使用 serial queues。
- Pattern:如果使用 `sleep(1)` 或固定延迟且这些延迟在 CI 上太短,属于 Hardcoded timeouts;修复方式是改用基于条件的等待,而不是固定延迟。
- Pattern:如果一个测试修改了另一个测试依赖的全局/静态状态,属于 Test pollution;修复方式是在 setUp/tearDown 中重置状态,或让每个测试使用独立实例。
- Pattern:如果共享 singletons 在测试之间携带状态,属于 Singleton contamination;修复方式是注入依赖或重置 singletons。
- Pattern:如果测试留下文件并影响后续运行,属于 File system leftovers;修复方式是使用临时目录并清理。
- Pattern:如果测试访问真实网络服务且服务可能慢或不可用,属于 Network calls;修复方式是 mock 网络调用。
- Pattern:如果测试依赖当前时间或时区,属于 Date/time sensitivity;修复方式是注入 clock 或冻结时间。
- Pattern:如果测试使用在不同环境中有差异的硬编码文件系统路径,属于 File system paths;修复方式是使用相对路径或临时目录。
- Pattern:如果测试只有在另一个测试先设置所需状态后才能通过,属于 Implicit ordering;修复方式是让每个测试自包含。
- Pattern:如果测试单独运行正常但并发运行时失败,属于 Parallel execution conflicts;修复方式是让每个测试使用唯一资源。
- Crash:如果 `crash_report` 显示 `EXC_BREAKPOINT` 或 `SIGTRAP`,识别为 force-unwrap nil 或 Swift precondition failure 等问题。
- Crash:如果 `crash_report` 显示 `EXC_BAD_ACCESS` 或 `SIGSEGV`,识别为 use-after-free 或 dangling pointer 等问题。
- Crash:如果 `crash_report` 显示 `EXC_CRASH` 或 `SIGABRT`,识别为未捕获的 Objective-C exception 等问题。
- Fix Implementation:应用能解决根因的最小修复。
- Fix Implementation:不要重构无关代码。
- Fix Implementation:如果修复需要 test utility(如 mock 或 helper),先检查是否已存在,再决定是否创建新的。
- Verification:使用 `xcodebuild test -workspace <workspace> -scheme <scheme> -only-testing <module>/<suite>/<test> -test-iterations <count> -run-tests-until-failure` 反复运行测试直到失败。
- Verification:根据测试耗时选择 iteration count;快的单元测试用 50–100,慢的集成或验收测试用 2–5。
- Verification:修复前先尝试在本地复现 flaky failure;成功复现能确认根因分析,并让你直接验证修复。
- Verification:使用重复运行方式,或在怀疑并发问题时使用下面的 race condition 复现策略。
- Verification:对于竞态条件、CI 特定时序问题或环境依赖失败,可能很难或无法本地复现;合理尝试后仍无法复现时,基于代码分析和失败日志继续修复。
- Verification:如果修复有明确 bug 证据,例如未同步的共享状态或 TOCTOU 模式,即使没有本地复现也有效。
- Race Condition:按顺序尝试策略 1:增加并行,添加 `-parallel-testing-enabled YES` 来并发运行测试套件。
- Race Condition:按顺序尝试策略 2:运行更广的测试套件,例如用 `-only-testing ModuleTests` 运行整个模块,以增加共享资源竞争。
- Race Condition:按顺序尝试策略 3:启用 Thread Sanitizer 运行 `xcodebuild test -workspace <workspace> -scheme <scheme> -only-testing <module> -enableThreadSanitizer YES` 以检测 data races;注意 TSan 会增加开销并改变时序,某些竞态可能不触发。
- Race Condition:按顺序尝试策略 4:结合以上方法,高迭代次数加广范围运行,例如完整模块、并行和多迭代。
- Race Condition:如果竞态无法本地复现,但代码可证明线程不安全,例如未同步修改共享状态,修复仍然有效。
- Race Condition:用相同的复现策略确认修复后测试通过。
- Race Condition:在 commit message 中记录该修复解决了通过代码分析和失败日志识别出的 CI-only race condition。
- Done Checklist:确认已识别 flakiness 的根因。
- Done Checklist:确认已应用针对性修复。
- Done Checklist:确认测试多次运行均稳定通过。
- Done Checklist:确认未引入新的测试依赖或共享状态。
- Done Checklist:用描述性 message 提交修复。
适用边界 · 注意事项
- 项目未接入 Tuist test insights,或没有可用的 Tuist CLI/账号时,无法执行这些发现、调查和指标查询步骤。
- 没有代码证据、失败日志或可复现线索时,不应仅凭猜测修改测试代码。
- 需要进行大规模重构或修改无关代码时,不适用;该技能要求做针对根因的最小修复。