通过上面的米色未完全覆盖行 – if(arg1 >0 && arg2 < 0),我们可以看出同一行代码不一定属于同一个block,有可能一个代码行中包含了多个block。那么可不可以说同一个block的内容一定全在同一行上?要回答这个问题,我们可以先看一下Visual Studio到底将GetInteger划分几个block。
通过上面的Code Coverage窗口中显示的覆盖数据结果,可以看出GetInteger一共被划分为 2 + 5 = 7 个block,其中未覆盖的block有2个。很显然,米色未完全覆盖行中肯定包含一个未覆盖block,那么剩下的一个只能可能是下面的“{”行和“return 1;”行。也就是说,“{” 和 “return 1;”这两行被认为是一个block,所以说同一个block的内容不一定全在同一行上,它有可能是分布在多行上,如下图所示:
综上所述,block和代码行之间没有非常规律的对应关系。那么到底block是如何定义的呢?MSDN:Code Coverage Data Overview 给出了如下的定义:
A code block is a code path with a single entry point, a single exit point, and a set of instructions that are all run in sequence. A code block ends when it reaches a decision point such as a new conditional statement block, a function call, exception throw, enter, leave, try, catch, or a finally construct. |
简单的说,就是有个单一入口和单一出口的代码块就被认为是一个block,但是这样的定义实际上是很难和代码直接对应上。之所以这样,是因为Visual Studio进行的instrument是针对IL或者(二进制)代码级别的而不是文本代码级别的。例如:GetInteger一共有7个block,能够直接从代码中识别出的有block (1,2,3,4),如下图所示。而block 5中实际上是包括3个block,我等凡夫俗子单凭肉眼是很难准确区分出这3个block的。
在一般的代码覆盖应用中,我们不必关心的block到底是如何定义和划分的,代码覆盖的核心用途是要发现已有测试所遗漏的产品代码,而这些被测试遗漏代码在“彩色”代码窗口已经可以很清楚地找到。如果要真想了解你的代码是如何被划分block,办法也是有的: 针对.NET语言,ildasm.exe就是这样的工具,用它来查看instrumented后的IL代码,并和未instrument的IL进行比较,你就会发现其中的奥秘。此时,对照着上面给出的code block的定义,可以更清晰地体会“单一入口和单一出口的代码块”的含义。在后面的博客中,将会花些时间具体介绍。
相关链接: