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

简介:

<professional software testing with visual studio 2005 team system tools for software developer>中提到了代码覆盖率,我很久没有去书店了,不知道是不是出了新的版本,觉得书里面关于代码覆盖率方面的知识有些地方没有讲,在这里补充一下。先回顾一下如何

查看代码覆盖率

 创建一个C#工程WildChar(无所谓是类型库工程还是命令行程序工程),假设我们要写一个将字符串按单词成对反转的程序。将下面的代码贴到工程的一个cs文件中:

Program.cs

public static string ReverseStringPair(string input)

{

    if (string.IsNullOrEmpty(input))

        throw new ArgumentNullException("input");

 

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

    int resultIter = 0;

 

    ReverseStringPairImp(input, 0, result, resultIter);

 

    return new string(result);

}

 

private static void ReverseStringPairImp(string input, int inputIter, char[] result,int resultIter)

{

    // skip white space

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

 

    int[] indics = new int[2] {

        inputIter, // first word begin index,

        0 // second word begin index

    };

 

    for (; inputIter < input.Length; ++inputIter)

    {

        if (input[inputIter] == ' ')

        {

            if (indics[1] == 0)

                indics[1] = -1;

            else if (indics[1] > 0)

                break;

        }

        else if (input[inputIter] != ' ' && indics[1] == -1)

            indics[1] = inputIter;

    }

 

    // copy second word, inputIter points to the end of second word

    if (indics[1] > 0)

    {

        for (int i = indics[1]; i < inputIter; ++i)

            result[resultIter++] = input[i];

 

        indics[1]--;

        // copy white space

        while (indics[1] >= 0 && input[indics[1]] == ' ')

            indics[1]--;

 

        result[resultIter++] = ' ';

    }

    else

        indics[1] = input.Length - 1;

 

    // copy the first word

    for (int i = indics[0]; i <= indics[1]; ++i)

        result[resultIter++] = input[i];

 

    // next pair

    if (inputIter < input.Length)

    {

        result[resultIter++] = ' ';

        ReverseStringPairImp(input, inputIter, result, resultIter);

    }

}

 

创建单元测试用例

把鼠标放在ReverseStringPair函数的声明上(或者说第一行),点击右键,并且选择“创建单元测试”命令,一切按照默认的设置选择“确定”按钮,创建一个测试工程。

在新创建的测试工程自动添加的programtest.cs(因为类名叫做program)文件里,添加一个新测试用例:

Programtest.cs

....

 

[TestMethod()]

public void ReverseStringPairTest()

{

    string input = "ab cd ef gh";

    string expected = "cd ab gh ef";

    string actual = Program.ReverseStringPair(input);

    Assert.AreEqual(expected, actual);

}

单元测试用例创建好了以后,点击工具栏里面的“Run Tests in Current Context”,就能看到测试结果了,如下图所示:

启用代码覆盖率测试

只执行单元测试是不能检查代码覆盖情况的即你创建的测试用例总共覆盖了多少行源代码。为什么需要特意开启代码覆盖率测试是有原因的,这个在文章的最后会讲到。

1.       在“解决方案浏览器(Solution Explorer)”里,双击“localtestrun.testrunconfig”文件。

2.       在弹出的“localtestrun.testrunconfig”窗口里,双击“代码覆盖率(Code Coverage)”。

3.       里面会列出好几个文件,有.dll ,也会有.exe。勾选你要测试代码覆盖率的程序,比如说你要测试WildChar工程也就是我们的产品代码的代码覆盖率,请勾选WildChar.exe。不要勾选包含测试用例的那个dll文件,因为我们对测试代码本身的覆盖率没有任何兴趣。结果如下图所示:

4.        点击“应用(Apply)”关闭窗口。

在重新运行一下所有的测试用例,点击测试结果窗口工具栏最右边的按钮,查看代码覆盖率情况,如下图所示:

代码覆盖率是按百分比计算的,即 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;

实际上这也正是visual studio在后台为我们悄悄做的工作,当然啦,Visual Studio不会直接在原来项目编译出来的文件作更改,它会将文件(wildchar.exe)拷贝一份,然后再拷贝上进行更改,更改后的程序文件会存放在解决方案文件夹的Test Result文件夹里以测试结果命名的文件夹中,例如我的修改过的可执行文件存放在:

E:\临时文档\WildChar\TestResults\施懿民_SHIYIMIN 2009-12-19 01_02_22\Out\

使用ILDASM.exe(或者reflector.exe)你就可以看出来,例如下面就是修改过后的IL 代码:

.method private hidebysig static void ReverseStringPairImp(string input,

                                                            int32 inputIter,

                                                            char[] result,

                                                            int32 resultIter) cil managed

{

 // Code size       1333 (0x535)

 .maxstack 5

 .locals init ([0] int32[] indics,

           [1] int32 i,

           [2] bool CS$4$0000,

           [3] int32[] CS$0$0001)

 IL_0000: call       void Microsoft.VisualStudio.Coverage.Init_c292aced4dea6d28292bbb91547781d7::Register()

// 下面就是 Visual Studio自动为我们添加的跟踪代码覆盖率的代码:

 IL_0005: ldsfld     uint32[] Microsoft.VisualStudio.Coverage.Init_c292aced4dea6d28292bbb91547781d7::m_vscov

 IL_000a: ldc.i4     0xa

 IL_000f: ldelem.u4

 IL_0010: ldc.i4     0xa

 IL_0015: add

 IL_0016: ldc.i4.1

 IL_0017: stind.i1

 IL_0018: nop

 IL_0019: br.s       IL_0033

 IL_001b: ldsfld     uint32[] Microsoft.VisualStudio.Coverage.Init_c292aced4dea6d28292bbb91547781d7::m_vscov

 IL_0020: ldc.i4     0xa

 IL_0025: ldelem.u4

 IL_0026: ldc.i4     0xb

 IL_002b: add

 IL_002c: ldc.i4.1

...

} // end of method Program::ReverseStringPairImp

 

使用代码覆盖率的注意事项

1.       代码覆盖率只能告诉你产品代码还有哪些地方、哪些功能模块没有测试到,或者说很仔细地测试过。不能告诉你比如测试效果是否已经足够好了,比如说代码覆盖率为100%不能说明你已经把用户的需求都考虑并且测试到了。请考虑下面的代码:

Int a = b * c;

Console.WriteLine(a);

如果c的值很小的话,那么 后面的Console那句就会执行,如果我们先执行这个测试用例,那么Console那句就会被标注为已经覆盖过,而且是100%覆盖过。但是并不没有测试到bc很大造成整数溢出异常这种情形。

 

2.       另外,代码覆盖率并不是自动化测试才能检查的,如果你的自动化测试用例不够,你完全可以把Visual Studio修改过的程序拷贝出来,手工执行一些测试用例。不管是自动化还是手工的测试用例,只要能够执行为覆盖的产品代码,最后 Visual Studio在统计结果的时候,都会统计进去(当然,手工用例的执行,应该在 Visual studio统计结果之前执行通常就是一次Test Run执行完毕之前)。

标签:  测试

本文转自 donjuan 博客园博客,原文链接:  http://www.cnblogs.com/killmyday/archive/2009/12/19/1627994.html  ,如需转载请自行联系原作者
相关文章
|
1天前
|
测试技术
软件质量保护与测试(第2版)学习总结第十三章 集成测试
本文是《软件质量保护与测试》(第2版)第十三章的学习总结,介绍了集成测试的概念、主要任务、测试层次与原则,以及集成测试的不同策略,包括非渐增式集成和渐增式集成(自顶向下和自底向上),并通过图示详细解释了集成测试的过程。
10 1
软件质量保护与测试(第2版)学习总结第十三章 集成测试
|
1天前
|
测试技术
软件质量保护与测试(第2版)学习总结第十章 黑盒测试
本文是《软件质量保护与测试》(第2版)第十章的学习总结,介绍了黑盒测试的基本概念和方法,包括等价类划分、边界值分析和因果图法,并通过具体例子展示了如何设计测试用例来验证软件的功能性需求。
10 1
软件质量保护与测试(第2版)学习总结第十章 黑盒测试
|
1天前
|
人工智能 人机交互 数据库
软件质量保护与测试(第2版)学习总结第一章
本文是《软件质量保护与测试》(第2版)第一章的学习总结,概述了软件的特征、分类、软件工程的层次化技术、现代软件开发的变化,以及软件质量的概念和评价体系,包括黑盒、白盒和灰盒测试方法。
6 1
软件质量保护与测试(第2版)学习总结第一章
|
1天前
|
测试技术
软件质量保护与测试(第2版)学习总结第十一章 白盒测试
本文是《软件质量保护与测试》(第2版)第十一章的学习总结,详细讲解了白盒测试中的控制流测试技术,包括语句覆盖、判断覆盖、条件覆盖、判定-条件覆盖和路径覆盖等方法,并通过具体代码示例展示了如何设计测试用例来验证程序中的不同执行路径。
7 2
|
1天前
|
安全 程序员 网络安全
Kali渗透测试:对软件的溢出漏洞进行测试
Kali渗透测试:对软件的溢出漏洞进行测试
|
1天前
|
安全 数据挖掘 测试技术
提升软件质量:探索高效测试策略
在软件开发过程中,测试是一个关键步骤,它决定了产品能否满足用户需求并保持高性能和安全性。本文将探讨几种有效的测试策略,包括自动化测试、性能测试和安全测试,以帮助开发团队提高软件质量。我们将分析每种方法的优势、实施步骤及面临的挑战,并提供实用的建议。
|
5天前
|
测试技术 数据安全/隐私保护 开发者
自动化测试的奥秘:如何用Selenium和Python提升软件质量
【9月更文挑战第35天】在软件开发的海洋中,自动化测试是那艘能引领我们穿越波涛的帆船。本文将揭开自动化测试的神秘面纱,以Selenium和Python为工具,展示如何构建一个简单而强大的自动化测试框架。我们将从基础出发,逐步深入到高级应用,让读者能够理解并实现自动化测试脚本,从而提升软件的质量与可靠性。
|
12天前
|
机器学习/深度学习 人工智能 安全
软件测试中的探索性测试:一种高效发现软件缺陷的方法
本文将深入探讨软件测试中的一种关键方法——探索性测试。探索性测试是一种动态的、探索性的软件测试方法,它依赖于测试人员的直觉和经验,通过实际操作软件来发现潜在的问题和缺陷。与传统的基于预定义用例的测试方法相比,探索性测试更加灵活,能够更全面地覆盖软件的各个方面,从而更有效地发现难以预见的错误和漏洞。
|
15天前
|
测试技术 持续交付 Python
自动化测试之美:打造高效的软件质量保障体系
【9月更文挑战第25天】在软件开发的海洋中,自动化测试是一艘能够引领我们高效航行的帆船。它不仅能帮助我们发现缺陷,更是一个持续集成和持续部署(CI/CD)过程中不可或缺的部分。本文将通过浅显易懂的语言和实际代码示例,引导读者理解自动化测试的价值,并学会如何实施它,从而提升软件的质量与开发效率。
34 4
|
14天前
|
敏捷开发 监控 测试技术
提升软件质量的利器:自动化测试的实践与反思
在软件开发的生命周期中,测试作为保障产品质量的重要环节,其重要性不言而喻。随着敏捷开发和持续集成等实践的普及,传统的手动测试方式已逐渐无法满足快速迭代的需求。因此,自动化测试作为一种提高测试效率和准确性的有效手段,正受到越来越多开发者的青睐。本文将深入探讨自动化测试的价值、实施步骤以及在实践中可能遇到的问题和解决方案,帮助读者更好地理解和应用自动化测试。
14 2