圈复杂度是什么
圈复杂度由 Thomas J. McCabe 在 1976 年提出:以控制流图上的判定点计数衡量分支规模,公式 M = E − N + 2P,也就是边数减节点数再加两倍连通分量,实践中约等于判定点个数加一。它同时给出分支测试数量的下界参考——复杂度为 4 的函数,至少要 4 条路径级用例才算覆盖到位。
基本信息
| 提出 | Thomas J. McCabe,1976 年论文 A Complexity Measure |
|---|---|
| 计算公式 | M = E − N + 2P,等价于 1 加判定点个数 |
| 常见阈值 | 约 10,属于经验值而非标准 |
| 主要用途 | 可测试性评估与模块拆分参考 |
典型使用场景
- 函数大到难以测试:先用复杂度找出最该拆的几个
- 评审判断风险:高复杂度叠加高频变更,通常是缺陷高发区
- 制定检查阈值:先看现状分布,再定多数函数能达到的目标值
- 排查历史缺陷集中区:热点分析中复杂度是常用的一维
- 评估测试充分性:复杂度给出分支用例数量的下界参考
哪些结构会被计入
- if 与 else if 分支
- for、while、do-while 循环
- switch 的 case 分支
- 部分工具把逻辑与或的短路求值也计入
- catch 块与三元表达式
计数示例
计数示例
int f(int a, int b) {
if (a > 0) { ... } // +1
while (b-- > 0) { ... } // +1
return a > b ? 1 : 0; // +1
}
// M = 1 + 3 = 4,至少需要 4 条路径级的用例取值区间与常见处理
| 复杂度 | 含义 | 常见处理 |
|---|---|---|
| 1 到 10 | 结构简单,容易测试 | 无需特别处理 |
| 11 到 20 | 分支较多,测试成本上升 | 评审时确认是否有必要拆分 |
| 20 以上 | 难以完整测试 | 优先拆分为多个函数 |
复杂度要配合变更频率一起看:高频改动且复杂度高的文件,才是优先重构的对象。
常见阈值属于经验值:它用于触发讨论与拆分判断,不适合直接拿来做个人考核。
不同工具的计算口径不一样:逻辑运算符是否计入、分支如何统计都会影响结果,跨工具比较之前先对齐规则。