软件自动化测试—代码覆盖率(2)

发表于:2015-04-24来源:uml.org.cn作者:不详点击数: 标签:自动化测试
代码覆盖率是按百分比计算的,即 Visual Studio会告诉你,有百分之多少的产品代码被覆盖了,而且你也可以查看单个函数的代码覆盖率,如下图所示: 在代

  代码覆盖率是按百分比计算的,即 Visual Studio会告诉你,有百分之多少的产品代码被覆盖了,而且你也可以查看单个函数的代码覆盖率,如下图所示:

  在“代码覆盖率结果”列表里双击每个函数名,你可以看到具体的代码覆盖信息,青绿色的代码是完全被覆盖到的,红色的代码是从来没有执行过的,而黄色的代码表示这一行有一部分代码被执行过—之所以说有一部分通常是因为一行代码有多个判断条件,有些条件执行了,有些却没有。如下图所示:

  代码覆盖率的实现原理

  看到这里,是不是有点神奇?为什么执行过一些自动化测试用例,就可以查看代码覆盖率呢?它是怎么实现的呢?

  实际上我们在“localtestrun.testrunconfig”窗口里面设置查看代码覆盖率那一步时,Visual Studio悄悄地修改了WildChar.exe,在原来的IL 代码里添加了一些新的语句。

  在解释之前,我们先考虑代码覆盖率的意思,代码覆盖率的意思其实就是表明有多少行代码被执行到了,因此首先要统计有多少块代码,然后再统计有多少块代码被执行了。什么叫代码块呢,代码块就是一段连续的代码。例如在program.cs里面,下面这些代码行组成一个代码块:

char[] result = new char[input.Length];

int resultIter = 0;
ReverseStringPairImp(input, 0, result, resultIter);
return new string(result);

  因为上面的代码,如果不ReverseStringPairImpl 函数不抛出异常的话,就会连贯地执行下去,因为上面四行代码可以看成是一块代码(或者说是一行代码)。

  而下面的代码则可以看成是两块代码:

if (indics[1] == 0)

    indics[1] = -1;

else if (indics[1] > 0)
   break;

  要么是第一个if执行,要么第二个if 执行。

  下面的代码会有点意思,虽然是一行代码,但是可以当作两个代码块来看待:

while (inputIter < input.Length && input[inputIter] == ' ')

  1. 要么前面一个条件成立,后面的条件不成立,那么最后一个语句不执行;

  2. 要么两个条件都成立,最后语句执行;

  3. 要么两个条件都不成立,最后一条语句不执行。

  由于第二个条件存在不被执行的机会—即我们设计的所有测试用例都导致第一个条件总是不成立,所以这也是为什么在显示代码覆盖率结果的时候,上面那行代码只有部分覆盖到的原因。

  有了代码块的概念之后,在实现代码覆盖率这个功能时,我们可以用一个大的布尔数组来保存有多少块代码被执行这个信息,而布尔数组的长度呢,就是程序的代码块的个数(因为一块代码可以看成一行代码)。也就是说,我们可以把产品代码手工修改成类似下面的样子:

bool pathCovered[] = new bool[11]; // 11是统计下来程序里面代码块的个数

for ( int i = 0; i < pathCovered.Length; ++i )
      pathCovered[i] = false;
// while (inputIter < input.Length && input[inputIter] == ' ') inputIter++;
firstblock:
    bool result = inputIter < input.Length;
    pathCovered[0] = true;
    if ( result )
    {
        result = input[inputIter] == ' ';
        pathCovered[1] = true;
    }
    else
    {
        pathCovered[2] = true;
        goto secondblock;
    }
    if ( result )
    {
        pathCovered[3] = true;       
        inputIter++;
       goto firstblock;
    }
secondblock:
    pathCovered[4] = true;       
    int[] indics = new int[2] {
        inputIter, // first word begin index,
        0 // second word begin index
    };
    for (; pathCovered[5] = true, inputIter < input.Length;

           pathCovered[6] = true, ++inputIter)
    {
        pathCovered[7] = true;
        if (input[inputIter] == ' ')
        {
           pathCovered[8] = true;
           if (indics[1] == 0)
            {
                pathCovered[9] = true;
                indics[1] = -1;
           }
            else if (indics[1] > 0)
            {
                pathCovered[10] = true;
              break;
            }
        }
    }
 
// 统计代码覆盖率信息
int covered = 0;
for ( int i = 0; i < pathCovered.Length; ++i )

{
    if ( pathCovered[i] ) covered++;
}
return covered / pathCovered.Length;

原文转自:http://www.uml.org.cn/Test/201306262.asp