软件自动化测试—代码覆盖率
在<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%覆盖过。但是并不没有测试到b和c很大造成整数溢出异常这种情形。
2. 另外,代码覆盖率并不是自动化测试才能检查的,如果你的自动化测试用例不够,你完全可以把Visual Studio修改过的程序拷贝出来,手工执行一些测试用例。不管是自动化还是手工的测试用例,只要能够执行为覆盖的产品代码,最后 Visual Studio在统计结果的时候,都会统计进去(当然,手工用例的执行,应该在 Visual studio统计结果之前执行—通常就是一次Test Run执行完毕之前)。
转载于:https://www.cnblogs.com/killmyday/archive/2009/12/19/1627994.html
软件自动化测试—代码覆盖率相关推荐
- 软件自动化测试培训内容,软件自动化测试与持续集成实践培训方案
一.背景概述 为响应工业和信息化部信息化高端人才培养的号召,中国信息化培训中心特推出了软件自动化测试与持续集成实践培训班,希望通过专业的培训与业界真实案例来全面提高学员软件自动化测试水平,从而更好地服 ...
- 软件自动测试框架,软件自动化测试框架的研究和实现
摘要: 软件自动化测试是软件工程领域的一项重要课题.随着软件工程理论的不断发展,软件自动化测试在理论上也不断达到新的高度.目前最为成熟的软件自动化测试技术是使用自动测试框架来指导自动化测试的实现.迄今 ...
- 打破软件自动化测试的格局
打破软件自动化测试的格局 自动化测试的误区 自动化测试仅仅被认为是替代人工,所以我们看到很多企业实施自动化测试仅仅是将现有的 Test Case 转换成自动化脚本. 这样做既没有提高测试整体水平,也没 ...
- 软件自动化测试成功之道_是什么使测试自动化成功?
软件自动化测试成功之道 测试是软件开发的一个重要但经常被低估的部分. 从定义上说,测试是具有挑战性的. 如果容易发现错误,那么它们就不会存在. 测试人员必须跳出框框思考,以发现其他人遗漏的错误. 在许 ...
- 软件自动化测试题,软件自动化测试模拟题.doc
PAGE PAGE 1 [模拟] 软件自动化测试 选择题 第1题: 不属于自动化测试实现方法的是 ______. A.测试过程的捕获和回放 B.测试脚本技术 C.测试管理技术 D.文档的静态分析技术 ...
- Eggplant 依托人工智能技术,改造软件自动化测试
数字化转型是疫情爆发以来最热门的一个方向,随着数字化转型的不断深入,软件的内容和价值也在飞速增长.软件工程师们努力工作,在社会生活的各个方面为大家提供丰富多彩的应用.他们在编写数百万行代码时,也会遇到 ...
- 软件自动化测试框架STAF
软件自动化测试框架STAF 一.什么是STAF STAF(Software Testing Automation Framework)是一个由IBM开发的开源.跨平台.支持多语言且基于可重用的组件来构 ...
- 手机软件自动化测试探索
手机软件自动化测试探索 作者:张元礼 http://blog.csdn.net/vincetest 手机软件测试面临的困境与挑战 手机行业也就是在最近短短的几年间以迅雷不及掩耳之势发展,起初手机 ...
- 软件自动化测试简介,1.1 自动化测试简介
***部分 基础篇 基础篇主要介绍两部分内容: 软件自动化测试概述和自动化测试工具QuickTest 的使用.目的是通过基础篇的学习, 使读者对软件自动化测试有一定的了解, 并能熟练使用自动化测试工具 ...
- 软件自动化测试可行性分析,基于 AI 的软件自动化测试思考与实践—kylinTOP 测试与监控平台...
对于一般的传统的自动化测试工具,如:Selenium,robotFramework,QTP等.QTP可以通过操作录制生成自动化用例脚本.生成的脚本与Selenium.robotFramework类似, ...
最新文章
- python对文件的操作模式_python对文件的操作
- 文本编辑器_国外程序员最爱的5种文本编辑器
- moxy json介绍_MOXy是GlassFish 4中新的默认JSON绑定提供程序
- [2013-08-19] nohup的使用
- r spgm 语言_Spatial Simultaneous Equations空间联立方程 的R package和经典文献
- 吴恩达机器学习课后作业深度解析(附答案)(ex2)
- ComponentArt Web.UI控件的bug及解决办法
- “能耗大户”数据中心供配电系统
- sqlplus 命令导入数据文件
- linux安装iscsi设备,linux系统下安装配置iSCSI教程
- 苦涩的技术我该怎么学?Akka 实战
- 转一篇千与千寻的影评。。。
- AD绘制PCB经验总结3-规则报警 Silk primitive without silk layer+Minimum Solder Mask Sliver
- 解决Kangle的Easypanel控制面板用户前台php版本无法切换的解决方法
- 损失函数大全Cross Entropy Loss/Weighted Loss/Focal Loss/Dice Soft Loss/Soft IoU Loss
- ppp lcp协商报文有哪些_课后分享PPP协议第十三周
- SRM 635 DIV2
- cd与cd /d命令
- 10进制转化为16进制的算法
- 火车头采集器V10下载-火车头采集器免费
热门文章
- android 控件字体反向,Android编程实现控件不同状态文字显示不同颜色的方法
- 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_14-MongoDb入门-文档...
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_3-1.整合Mybatis访问数据库和阿里巴巴数据源...
- 【Leetcode_easy】724. Find Pivot Index
- 【Python】使用torrentParser1.02对单文件torrent的分析结果
- js获取image中src属性的方法语句
- nested exception is java.io.FileNotFoundException: class path resource [spring/spring-datasource-mog
- Javascript模式——函数提升 (笔记)
- 15-07-22 数据库--存储过程、触发器
- Viewbox在UWP开发中的应用