`
tansitongba
  • 浏览: 503505 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

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

<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);

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

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

分享到:
评论

相关推荐

    测试代码覆盖率

    在标题中提到的“测试代码覆盖率”是指通过自动化测试来确定多少比例的代码被执行过,这对于确保软件质量、查找未被测试的代码区域至关重要。 Eclipse是一款广泛使用的集成开发环境(IDE),它提供了丰富的插件生态...

    软件测试中的自动化测试与代码覆盖率.pptx

    ### 软件测试中的自动化测试与代码覆盖率 #### 第一章:软件测试中的自动化测试与代码覆盖率 **自动化测试**是指使用特定的工具或脚本来执行预定义的测试用例,以验证软件产品的功能是否符合预期的行为。这种方式...

    代码覆盖率驱动的测试

    代码覆盖率驱动的测试是一种软件测试方法,其核心目标是通过测量代码执行过程中的覆盖率来指导测试活动,确保测试用例尽可能多地覆盖代码中的各种执行路径。代码覆盖率反映了在测试过程中执行到的代码行数与总代码...

    代码覆盖率工具

    代码覆盖率工具是软件开发过程中的重要辅助手段,主要用于评估测试代码对源代码的覆盖程度。...在实际开发中,结合持续集成和自动化测试,代码覆盖率工具能帮助团队实现更好的质量管理,降低软件缺陷,提高用户满意度。

    代码覆盖率eclipse插件

    安装完成后,需要在项目属性中配置测试运行配置,关联对应的JUnit测试类,这样在运行测试时,EClemma会自动计算代码覆盖率。 2. **代码覆盖率的计算** 代码覆盖率通常包括行覆盖率、分支覆盖率、条件覆盖率等多种...

    eclemma单元测试代码覆盖率工具

    EclEmma是一款强大的Java单元测试代码覆盖率工具,它为开发者提供了直观的方式来衡量和评估他们的单元测试的质量。在软件开发过程中,单元测试是确保代码正确性和可靠性的关键步骤,而EclEmma则帮助开发者确保测试...

    软件自动化测试

    ### 软件自动化测试的关键知识点 #### 一、软件自动化测试概述 软件自动化测试是一种利用专门的测试软件工具执行预定义的测试过程的方法。它主要用于替代人工手动测试的重复性和耗时的任务,以提高效率并减少人为...

    一种Java代码覆盖率工具的应用研究.pdf

    为了提高软件测试的效率和质量,出现了各种软件自动化测试工具。这些工具按照测试应用的角度可以分为几大类,包括白盒测试工具、黑盒测试工具、性能测试工具、测试流程管理、缺陷跟踪管理、测试用例管理等。这些工具...

    代码覆盖率驱动的测试资料.docx

    代码覆盖率是评估软件测试质量的重要指标之一,它度量了程序源代码被测试的程度。本文主要探讨了如何利用代码覆盖率工具EMMA来进行测试,并详细介绍了在Android工程中使用EMMA进行单元测试覆盖率检查的步骤。 EMMA...

    软件自动化测试基础

    总的来说,软件自动化测试是软件质量保证的关键环节,通过合理引入和有效利用自动化测试工具,可以显著提高测试的质量和效率,同时降低测试成本。然而,理解和掌握自动化测试的基础知识,包括其原理、方法和适用场景...

    TestEnvTest_chamberodm_自动化测试_自动化测试代码_

    自动化测试的优势在于可以快速执行大量重复的测试任务,减少人工介入的时间,提高测试覆盖率,并且能够更早地发现并修复潜在问题。 在文件名称列表中,我们看到"TestEnvTest.java",这是一个Java源文件,很可能是...

    在实时服务器上生成代码覆盖率报告

    配合PHPUnit这样的自动化测试框架,可以方便地生成覆盖率报告。"matthiasnoback-live-code-coverage-eeb964a"这个文件名可能是一个特定版本的代码覆盖率工具或者示例代码库,用于展示如何在实时服务器上实现这一功能...

    软件测试--自动化测试

    软件自动化测试是现代软件开发过程中的重要组成部分,它旨在提高测试效率、准确性和覆盖率,减少人力成本,并确保软件质量。本章将详细讲解自动化测试的基础、生命周期方法学及其应用,以及自动化测试工具的概述。 ...

    Android Native C++代码覆盖率统计 Demo(基于NDK 21)

    首先,代码覆盖率是衡量软件测试完整性的一个重要指标,它反映了测试用例执行时覆盖了多少源代码。对于C++代码,Android NDK提供了一种基于Clang的解决方案。Clang是LLVM项目的一部分,不仅是一个高效的C/C++/...

    4-前端质量利器-马可代码覆盖率平台.pdf

    【马可代码覆盖率平台】是专门针对前端质量监控和优化的一款工具,旨在解决在互联网技术开发过程中遇到的挑战,如代码冗余、测试覆盖率不足、自动化测试成本高等问题。该平台在2021年vivo开发者大会上被提及,特别...

Global site tag (gtag.js) - Google Analytics