在实践单元测试的过程中我们发现,在业务开发时没有一种标准或者方法论可以协助我们决定对哪些代码覆盖用例带来的收益更高,我们花了很多时间写单元测试,如何才能将这部分的产出最大化?如何让我们的用例都用在刀刃上?针对这些问题,正在写文档的我还在探索中。
从另一个角度讲,我们希望用例都用在刀刃上,刀刃在哪里,可以简单理解成风险较高的代码,针对任意的一段代码,局外人无法轻易从业务上分析其风险性,但是通过静态检测可以给出一些参考。这就是这篇文章的内容。
Visual Studio Code Metrics
这是Visual Studio自带的代码分析工具(可喜的是,针对此功能,专业版与企业版具有相同的功能),通过VS可以快速的对当前解决方案中的项目进行代码分析。通过点击 [分析]—>[计算代码度量值] 可以快速的得到分析结果,分析结果如下图:
- 可维护性指数:一个0~100的数值,数值越大可维护性越好。前面的颜色块用于快速显示当前可维护性,绿色等级介于 20 和 100 之间,表示代码的可维护性良好; 黄色等级介于 10 和 19 之间,表示代码的可维护性中等。;红色等级是介于 0 和 9 之间的等级,表示可维护性低
- 圈复杂度:这就是大家常规理解的圈复杂度啦,它是通过程序流中的不同代码路径数计算得来。数值越高,流程越复杂,风险也越高
- 继承深度:从顶层基类到当前类的继承深度
- 类耦合:通过参数、局部变量、返回类型、方法调用、泛型或模板实例化、基类、接口实现、在外部类型上定义的字段以及特性修饰来衡量与一个类的耦合程度
- 代码行数:代码中的大概行数
通过静态代码分析能辅助找到风险高的代码,然后针对性处理,重构也好,补充用例也好。
DotCover
DotCover除了做好覆盖率检查外,还提供了一个Detecting Hot Spots的功能,能够结合代码的圈复杂度和测试用例覆盖情况得出一个风险评估结果。如果你安装了Reharper和DotCover的VS插件,可以通过点击 [Resharper]—>[Unit Tests]—>[Cover All Tests from Solution] 得到下图的结果:
Hot Spots的计算规则是:
Risk(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)
Where:
m - method
comp(m) - cyclomatic complexity of the method
cov(m) - test coverage of the method by unit tests
Hot Spot加入了代码覆盖率的分析,能够更加精准的定位风险点。
指令级别的复杂度分析
常规的复杂度计算是在语言层面分析代码的分支情况,可以很好的辅助我们分析代码的复杂度,其计算规则是:
V(G)=e-n+2
其中,e表示控制流图中边的数量,n表示控制流图中节点的数量
指令级别的复杂度分析从语言和平台层面入手,以.NET平台为例,我们写的C#或VB代码,会先转换成IL指令(一种类似汇编语言的命令式语言),在代码中的每个判断都对应了某个指令,如果一个函数中判断指令很多,那么其复杂度也很可能较高。基于此,指令级别的复杂度分析也是我们复杂度分析的一个很好的辅助工具。
ILCyclomicComplextityCalculator是一个基于Mono.Cecil的IL复杂度分析工具,能够分析出一个托管dll的代码复杂度情况。
地址:https://github.com/erdao/CodeMetrics