为了保证代码质量,一般会要求提交的源码要有测试用例覆盖,并对测试覆盖率有一定的要求,在实践中不仅会考核存量代码覆盖率(总体覆盖率)还会考核增量代码的覆盖率。

或者说增量覆盖率更有实际意义,测试用例要随源码一并提交,实时保证源码的质量,而不是代码先行,测试用例后补,这有些应付的意思。

对于存量代码覆盖率主流的测试工具(框架)都是默认支持的,配置reporter相关参数,执行完测试用例就会生成测试报告。

对于增量测试覆盖率主流的测试工具一般没有支持,我想计算增量代码貌似不是测试工具该干的事,所以主流测试工具并没有提供这一功能。

那么如果计算增量覆盖率呢?

计算增量测试覆盖率,总共需要3步:

·计算出增量代码的所有行号

·计算出测试未覆盖的代码的所有行号

·对比计算增量代码被测试覆盖的比例,得出增量覆盖率

是不是很简单,有没有一种 “道理我都懂,就是过不好这一生的赶脚”

一、计算增量代码的所有行号

代码管理一般都会用到 GIT 这个工具,GIT提供了非常强大的管理增量代码的能力,因此,可以利用GIT这一特性,通过git diff(参考文献1) 这个命令获取增量代码。

git diff命令可以使用如下格式,用来对比不同commit(或分支)间的增量代码

git diff []

其中可以是分支名,对比分支间的差异,则是 git diff [] targetBranchName sourceBranchName。可以简写为 git diff targetBranchName 表示对比当前分支与目标分支间的代码增量差异。

例如 git diff master 生成当前分支与master分支的增量信息,当有多个文件变化时,会有多个这样的信息块。

·第1部分是发生变化的文件名。---表示文件发生了删除行 +++表示文件发生了新增的行,当---和+++后面是文件路径(相对代码根目录的相对路径)。

·如果某个文件是新增文件,则---后面是/dev/nul

·如果某个文件被删除了,则+++后面是/dev/nul

·如果文件发生修改,则---和+++后面都有文件名

·先介绍第3部分,因为第2部分的解读需要用第3部分辅助。第3部分是详细的含有上下文的增量信息(增量不是指增加,删除也算增量)

- 表示这一行被删除

+ 表示这一行是新增

如果某一行发生修改,则由一条-和一条+表示

·第2部分是变化的行号信息,以 @@开头和结尾,中间是删除的行号信息和新增的行号信息,以上图为例

-1,11表示,文件出现删除,从第1行开始包含上下文信息一共有11行,在第3部分中分别是第6, 8, 9, 10, 12, 13, 14, 15, 16, 17, 25 行,共11行

+1,18表示,文件出现新增,从第1行是包含上线文信息一共18行,在第3部分中分别是第7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25 行,共18行

其中,第8, 9, 10, 12, 13, 14, 15, 16, 25 行是上下文信息,真正删除的行是第6, 17 行,共2行; 新增的行是第7, 11, 18, 19, 20, 21, 22, 23, 24 行,共9行。

不难发现,git diff 默认给出的行号信息,不仅包含真正删除和增加的行,还包含一定的上下文信息(为的是给人看时,能看出到底改了哪些行信息,尤其在一个文件有很多相似或重复的语句的情况下)。并且在计算删除的行的行数时(-1,11中的11)要过滤掉增加的行后再计算,反之亦然(+1,18中的18)。

通过上面的命令确实能计算出增量代码的实际行号(有开始行号,有行数,有差异信息),但对于第3部分的差异信息的解析存在一定的难度,不仅要过滤掉对向信息,还要过滤掉上下文信息。

经查阅文档,发现git diff有一个options是--unified=,简写-U。使用此参数来决定diff结果中上下文信息显示n行,而不是默认的3行。

使用 git diff --unified=0 master 或 git diff -U0 master看运行结果:

数据结构与不带options的结果基本一致,只不过第2部分和第3部分作为一个整体可能会出现1次或多次,还有一点变化是第2部分行号信息的表达出现了三种格式。

-(+)后面只有一个数字,数字是,表示删除(增加)了1行,行号是。此例中-1, +1, +5, -10分别表示第1行删除1行,第1行增加1行,第5行增加1行,第10行删除一行。

-(+)后面有两个数字,第一个数字是,第二个数字是0, 表示删除(增加)了0行,即m行没有变化,此例中-4,0表示第4行没有变化

-(+)后面有两个数字,第一个数字是,第二个数字是,不是0,表示删除(增加了)n行,起始行号是m。此例中+11,7表示从第11行开始,共增加了7行,行号一次递增,即 11, 12, 13, 14, 15, 16, 17 这几行。

因此,计算增量代码的信息只使用第1部分和第2部分就可以完成,由第1部分计算出增量代码的路径,由第2部分的+后面的数字计算得到增量代码的行号(-后面是删除的行信息,不是增量代码)。本例中a.js文件的增量行号是[1, 5, 11, 12, 13, 14, 15, 16, 17]。

由于git diff生成的是固定格式纯文本,解析增量信息时可以按行读取字符串后做正则解析即可。对于linux系统,可以通过管道符|将diff文本导给grep命令(参考文献2),使用正则匹配出需要的信息,命令如下:

git diff -U0 master | grep -Po '^\+\+\+ ./\K.*|^@@ -[0-9]+(,[0-9]+)? \+\K[0-9]+(,[0-9]+)?(?= @@)'

生成结果如下图,此时,再按行遍历,生成以文件路径为Key,增量行号组成的Array为值的Hash表,用于后续逻辑的索引。

二、计算测试未覆盖的代码的所有行号

计算未被测试覆盖的行号,需要先在当前分支运行测试脚本生成对应的测试报告。

测试报告有很多种格式,其中http://lcov.info(参考文献3)是一种描述源码覆盖率的纯文本格式的文件,因此它非常便于计算,可利用此文件计算得到未被覆盖的行号。

http://lcov.info文件内容如下图:

数据包含以下字段,因工具不同,字段出现的顺序会略有变化

·TN: 用例名称,[因工具不同,有的无法生成此字段]

·SF: 源文件路径,[因工具不同,有的是绝对路径,有的是相对路径]

·FN:, 函数起始行号,函数名称,[因工具不同,有的函数名无法生成]

·FNDA:, 函数被执行次数,函数名称,[因工具不同,有的函数名无法生成]

·FNF: 识别统计到的函数数量

·FNH: 被测试覆盖的函数数量, FNH / FHF即函数覆盖率

·BRDA:,,, 条件分支所在行号,块号,分支号,被执行的次数

·BRF: 识别统计到的条件分支数量

·BRH: 被测试覆盖的条件分支数量 BRH / BRF 即分支覆盖率

·DA:,[,] 行号,执行次数, 检验和,[因工具不同,有的有校验和,有的没有]

·LH: 被测试覆盖的行数量

·LF: 可被执行的行数量, LH / LF 即行覆盖率

·end_of_record 统计信息块结束符,一个文件一个块

由此可见,计算未覆盖代码的行号,只需要提取覆盖率数据中SF和DA字段的值即可

·SF是源码文件路径

·DA字段有两个数字,第1个是行号,第2个是执行次数,半角逗号分隔,执行次数的值是0的即是未被覆盖的行

同解析diff增量数据一样,解析覆盖率数据时也可以按行读取字符串后做正则解析即可。对于linux系统,可以通过管道符|连接cat和grep命令(参考文献2),使用正则匹配出需要的信息,命令如下

cat coverage/lcov.info | grep -Po '^SF:\K.*|^DA:\K[0-9]+(?=,0)'

生成的结果如下图,得到未被覆盖的行号,再按行遍历,生成以文件路径为Key,增量行号组成的Set为值的Hash表,用于后续逻辑的索引:

三、最后一哆嗦

得到上面两份数据,就可以计算得出每个文件的增量覆盖率和总体增量覆盖率了。

但还需要考虑一种情况:由于一些原因(可是配置文件的问题)导致一些源码文件未被统计到测试覆盖率报告中,那么 + 有意为之,则增量文件不用计入增量覆盖率中,此文件的增量覆盖率是 100% + 无意为之,则增加文件需要计入增量覆盖率中,此文件的增量覆盖率是 0

伪代码如下:

const incData = {       // 增量代码行号Hash表

'path/a.js': [1, 2, 3],

'path/b.js': [2, 3, 4],

...

}

const notCovData = {    // 未覆盖代码行号的Hash表

'path/b.js': 'Set(3) {1, 2, 3}',

'path/c.js': 'Set(3) {1, 2, 3}',

...

}

let notCovLintCount = 0

let lineCount = 0

forEach(incData, (data, file) => {

const notCovSet = notCovData.get(file)

const notCovLines = []

if (notCovSet) {     // 如果增量代码文件中有未覆盖的行数

forEach(data, lineNum => {

if (notCovSet.has(lineNum)) {

notCovLines.push(lineNum)

}

})

} else {    // 增量代码的文件没有被测试覆盖到

if (!ignore) {  // 如果是无意为之,所有行号均被统计

notCovLines = notCovLine.concat(data)

}

}

console.log(file, '增量覆盖率:', (1 - notCovLines.length / data.length).toFixed(2) + '%')

lineCount += data.length

notCovLineCount += notCovLines.length

})

console.log('总体增量覆盖率:', (1 - notCovLintCount / lineCount).toFixed(2) + '%')

至此,分支间的增量代码的测试覆盖率计算完成。

详细的实现逻辑可参考 nodejs版本

实践与应用

·一般会用于CI检测中,在test step后添加增量覆盖率检测脚本,增量覆盖率未达标的代码禁止并入代码库

·也可用于git hook中做检测(这会增加提交代码的等待时长,不太建议),增量覆盖率未达标的代码禁止提交。

本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理

软件测试用例覆盖率怎么算,如何计算增量测试覆盖率相关推荐

  1. iOS 覆盖率检测原理与增量代码测试覆盖率工具实现

    背景 对苹果开发者而言,由于平台审核周期较长,客户端代码导致的线上问题影响时间往往比较久.如果在开发.测试阶段能够提前暴露问题,就有助于避免线上事故的发生.代码覆盖率检测正是帮助开发.测试同学提前发现 ...

  2. ios 单元测试覆盖率怎么查看_iOS 覆盖率检测原理与增量代码测试覆盖率工具实现...

    背景 对苹果开发者而言,由于平台审核周期较长,客户端代码导致的线上问题影响时间往往比较久.如果在开发.测试阶段能够提前暴露问题,就有助于避免线上事故的发生.代码覆盖率检测正是帮助开发.测试同学提前发现 ...

  3. 多环境多需求并行下的代码测试覆盖率统计工具实现

    个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈 测试覆盖率常被用来衡量测试的充分性和完整性,也是测试有效性的一个度量.「敏捷开发」的大潮之下,如何在快速迭代的同时保证对被测代码的覆 ...

  4. 软件测试用例优秀例子_功能测试用例设计方法分享

    测试用例可以用来衡量一个项目测试质量,因此在平时的测试流程中,编写测试用例就是测试过程中很重要的一步,每一个测试工程师都需要并且非常熟练的编写测试用例,能在编写测试用例中尽可能的覆盖任何异常的测试点: ...

  5. 测试覆盖率是软件测试的重要组成部分?当然是,必须是啊!

    摘要: 就软件质量而言,测试覆盖率是软件测试中的重要指标.接下来一起了解测试范围.测试技术,测试标准以及如何改进它.由于软件中普遍存在的错误,全世界都见证了一些灾难性事件.2008年在英国希思罗机场5 ...

  6. 测试覆盖率之一——测试覆盖率分类(转)

    转一篇,别人写的关于覆盖率的文章,没事常看看琢磨琢磨 测试覆盖率之一--测试覆盖率分类(转) 关于覆盖率,网络上最常见的两个词应该是"测试覆盖率"(Test Coverage)和& ...

  7. 测试覆盖率工具--EMMA

    测试覆盖率(Code Coverage) 测试覆盖率,简单的说,就是评价测试活动覆盖产品代码的指标.测试的目的,是确认产品代码按照预期一样工作,也可以看作是产品代码工作方式的说明文档.进一步考虑,测试 ...

  8. Go测试覆盖率 - Goc

    先聊聊,为什么要有测试覆盖率? 设想以下场景: 1,自动化组,长期做接口黑盒测试 2,业务组,针对单项目做系统测试 这种情况,会导致对所测系统的覆盖度未知.而综合覆盖率收集系统,尤其适合没有白盒测试的 ...

  9. matlab 测试覆盖率分析,简单几步分析测试覆盖率

    太久没有更新博客了,当初承诺的周更快变成月更了,(⊙﹏⊙)b 上次介绍了单元测试的重要性和如何开始写单元测试,今天再推荐给大家一种分析测试覆盖率的工具NUnit.本文测试环境为windows 10 + ...

  10. .Net core基于xUnit的单元测试查看测试覆盖率

    写代码如何保证代码质量,基本大家都知道要做单元测试,那如何知道你单元测试是不是测试到了所有代码场景呢,这就要通过测试覆盖率来体现了. 测试覆盖率,一般来说主要是Line代码行数覆盖率,同样还会有Bra ...

最新文章

  1. IT小小鸟VS.小小小鸟:展翅,我们一起翱翔!
  2. 【每日算法】桶排序算法
  3. powerdesigner基本使用 - 创建概念模型
  4. Elasticsearch-集群原理
  5. cv2 imshow窗口大小_cv2.imshow()图片无法显示
  6. 挖槽!堪称神级的Java技术手册火了???(文末送书活动)
  7. (转) 微软项目管理培训笔记(一)
  8. springboot+jsp+mybatis项目实例(后台成功,但是无法跳转jsp页面,没有实体类的注解,看springboot+jsp第二弹相关配置,即可成功配置jsp)...
  9. mysql 多点在 多边形,在MySQL中获取多点空间数据
  10. 宿命传说2之女神召唤java_热血传奇:传奇那些传说中的秘密,连骨灰级的玩家都未必知道...
  11. 【优化分类】基于matlab改进的人工蜂群算法优化SVM分类【含Matlab源码 1833期】
  12. 0906--学成在线页面案例
  13. 剖析车联网的完美形态,机器人化还是智能交通?
  14. unity3d 词典访问_正确的词典访问方式
  15. 计算机科学人工智能的应用,计算机人工智能技术的应用与发展.pdf
  16. fiddler 手机代理上网 通过代理服务器进行身份验证失败
  17. OneTab Plus|标签管理大师
  18. 爪哇国新游记之三十二----邮件发送
  19. 哗哗地照样子写词语_描写哗哗的词语
  20. 网易2018校园招聘:合唱 [python]

热门文章

  1. Ruby语言的特别之处
  2. 左拥快手右抱抖音,丁磊直播究竟图什么?
  3. BZOJ 5477: 星际穿越
  4. pow是什么意思python,python中pow什么意思
  5. 8款实用的Jquery瀑布流插件
  6. android微信认证失败怎么办,微信登陆好友头像验证失败该怎么办?
  7. Mybatis“四大神兽”
  8. 移动Win7用户文件夹(我的文档)默认位置至D盘
  9. 计算机骂人的专业术语,台湾网友分享“如何用本专业术语骂人不带脏字”
  10. 邮件安全证书(S/MIME),如何申请邮件证书