你下去研究,可以按这张知识地图来,不要散着看。
1. 单元测试层
先搞清楚测试框架负责什么:
XCTest
Apple 官方单元测试框架。
负责发现测试方法、执行测试、断言结果。
测试用例
负责调用业务代码,让目标函数、分支、异常路径真的运行。
Mock / Fake / Stub
测试替身。
用来替代真实依赖,控制返回值、制造异常、隔离外部环境。
重点结论:
XCTest 不计算覆盖率。
Mock 不计算覆盖率。
它们负责让业务代码执行到指定路径。
2. 覆盖率计算层
覆盖率总公式:
覆盖率 = 已执行数量 / 纳入统计的总数量
常见指标:
行覆盖率
被执行过的可执行代码行 / 纳入统计的可执行代码行总数
函数覆盖率
被调用过的函数 / 纳入统计的函数总数
分支覆盖率
被执行过的 true/false 分支路径 / 纳入统计的分支路径总数
Region 覆盖率
LLVM 更细粒度的代码区域覆盖率
重点结论:
函数覆盖了,不代表分支都覆盖。
行覆盖了,也不代表所有条件路径都覆盖。
分支覆盖率比行覆盖率更严格。
3. 编译插桩层
Xcode 打开覆盖率:
xcodebuild test -enableCodeCoverage YES
底层 clang 会带:
-fprofile-instr-generate
-fcoverage-mapping
含义:
-fprofile-instr-generate
生成覆盖率计数器和运行时采集逻辑。
-fcoverage-mapping
生成源码位置和计数器之间的映射关系。
流程:
Objective-C 源码
↓
Clang 解析
↓
LLVM IR
↓
LLVM 插桩
↓
机器码 / 二进制
↓
XCTest 执行
重点结论:
插桩不是改 .m 源码。
插桩是在编译过程中给中间代码/二进制加入计数器。
测试运行到哪里,对应计数器就 +1。
4. 运行采集层
测试运行时:
XCTest 调用业务代码
业务代码执行到函数/行/分支
LLVM 计数器增加
测试结束写出 .profraw
Xcode/llvm-profdata 合并为 Coverage.profdata
报告生成需要两类东西:
测试二进制
保存源码映射、函数信息、覆盖率 section。
Coverage.profdata
保存运行后的计数结果。
重点结论:
profdata 单独不是完整报告。
llvm-cov 需要"测试二进制 + profdata"才能还原源码覆盖率。
5. 报告工具层
常见文件:
xccov-report.txt
Xcode 行覆盖率视图,适合快速看文件/方法覆盖率。
llvm-cov-report.txt
LLVM 汇总报告,能看 region、function、line、branch。
OCBillingCalculator.llvm-cov.txt
源码逐行报告,能看每行执行次数和分支 true/false 次数。
cobertura.xml
给 GitLab/Jenkins 读取的机器报告,不适合直接当完整人工报告。
HTML 报告
给人看的详细覆盖率报告。
重点结论:
CI 读 cobertura.xml。
人看 llvm-cov HTML / genhtml / 源码逐行报告。
6. 统计口径层
一定要区分:
代码执行了
代码进入覆盖率分母
它们不是一回事。
通常业务覆盖率要排除:
测试代码
Mock/Fake 辅助类
三方库
系统库
build 目录
生成代码
main/AppDelegate 等非核心业务入口
重点结论:
排除分母不是说代码不能运行。
而是说它不属于业务覆盖率考核对象。
7. 常见争议点
Mock:
Mock 驱动到的业务代码会计入覆盖率。
Mock 对象自己的测试辅助代码通常不纳入业务覆盖率分母。
try/catch:
catch 不是不能覆盖。
没有异常用例时不会覆盖。
通过 mock 抛异常或构造异常输入,可以覆盖 catch。
#if DEBUG:
这是编译期条件。
当前构建没编译进去的分支,不进入当前覆盖率分母。
Debug 跑不到 Release 的 #else,因为它根本不在 Debug 产物里。
75%:
能不能达到取决于统计口径。
业务代码行覆盖率 75% 是可以做到的。
全工程含三方库/系统代码/老旧不可测代码的分支覆盖率 75% 可能很难。
不可覆盖代码:
真正不可达代码
强依赖硬件/系统环境
异常路径不可制造
多线程竞态
编译条件分支
设计不可测试
处理方式:
补用例
Mock/Fake
依赖注入
重构
排除分母
记录合理未覆盖风险
8. 你重点研究这些关键词
XCTest
Mock / Fake / Stub
Code Coverage
Line Coverage
Function Coverage
Branch Coverage
LLVM Source-based Code Coverage
Clang
LLVM IR
Instrumentation
-fprofile-instr-generate
-fcoverage-mapping
profraw
Coverage.profdata
llvm-profdata
llvm-cov show
llvm-cov report
xccov
Cobertura XML
coverage denominator
exclude / ignore filename regex
9. 官方资料优先看
建议顺序:
1. Clang Source-based Code Coverage
2. llvm-cov command guide
3. Apple XCTest / Xcode Code Coverage / xccov
4. GitLab Cobertura coverage_report
5. Jenkins Coverage plugin / Cobertura / LCOV 支持
10. 你现场要记住的总框架
测试层:
XCTest / Mock 负责让业务代码跑到。
编译层:
Clang / LLVM 负责插桩。
运行层:
计数器记录执行次数,生成 profraw/profdata。
报告层:
llvm-cov / xccov / GitLab 负责展示。
口径层:
通过 ignore/filter 控制哪些代码进入业务覆盖率分母。
最重要的一句话:
覆盖率统计的是:当前编译产物中、纳入统计范围的可执行代码,在测试运行时有没有被执行到。