代码覆盖率

news2024/12/23 18:17:05

在做单元测试时,代码覆盖率常常被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况,比如,代码覆盖率必须达到80%或 90%。于是乎,测试人员费尽心思设计案例覆盖代码。用代码覆盖率来衡量,有利也有有弊。本文我们就代码覆盖率展开讨论,也欢迎同学们踊跃评论。

首先,让我们先来了解一下所谓的“代码覆盖率”。我找来了所谓的定义:

代码覆盖率 = 代码的覆盖程度,一种度量方式。

上面简短精悍的文字非常准确的描述了代码覆盖率的含义。而代码覆盖程度的度量方式是有很多种的,这里介绍一下最常用的几种:

1. 语句覆盖(StatementCoverage)

又称行覆盖(LineCoverage),段覆盖(SegmentCoverage),基本块覆盖(BasicBlockCoverage),这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,因此就不会包括像C++的头文件声明,代码注释,空行,等等。非常好理解,只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{} 也常常被统计进去。语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。假如你的上司只要求你达到语句覆盖,那么你可以省下很多功夫,但是,换来的确实测试效果的不明显,很难更多地发现代码中的问题。

这里举一个不能再简单的例子,我们看下面的被测试代码:

int foo(int a, int b)
{
   return  a / b;
}


假如我们的测试人员编写如下测试案例:

TeseCase: a = 10, b = 5

测试人员的测试结果会告诉你,他的代码覆盖率达到了100%,并且所有测试案例都通过了。然而遗憾的是,我们的语句覆盖率达到了所谓的100%,但是却没有发现最简单的Bug,比如,当我让b=0时,会抛出一个除零异常。

正因如此,假如上面只要求测试人员语句覆盖率达到多少的话,测试人员只要钻钻空子,专门针对如何覆盖代码行编写测试案例,就很容易达到主管的要求。当然了,这同时说明了几个问题:

    1.主管只使用语句覆盖率来考核测试人员本身就有问题。

    2.测试人员的目的是为了测好代码,钻如此的空子是缺乏职业道德的。

    3.是否应该采用更好的考核方式来考核测试人员的工作?

为了寻求更好的考核标准,我们必须先了解完代码覆盖率到底还有哪些,如果你的主管只知道语句覆盖,行覆盖,那么你应该主动向他介绍还有更多的覆盖方式。比如:

2. 判定覆盖(DecisionCoverage)

又称分支覆盖(BranchCoverage),所有边界覆盖(All-EdgesCoverage),基本路径覆盖(BasicPathCoverage),判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到了。这句话是需要进一步理解的,应该非常容易和下面说到的条件覆盖混淆。因此我们直接介绍第三种覆盖方式,然后和判定覆盖一起来对比,就明白两者是怎么回事了。

3. 条件覆盖(ConditionCoverage)

它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别,我们来举一个例子,假如我们的被测代码如下:

int foo(int a, int b)
{
    if (a < 10 || b < 10) // 判定
    {
        return 0; // 分支一
    }
    else
    {
        return 1; // 分支二
    }
}


设计判定覆盖案例时,我们只需要考虑判定结果为true和false两种情况,因此,我们设计如下的案例就能达到判定覆盖率100%:

TestCaes1: a = 5, b = 任意数字  覆盖了分支一
TestCaes2: a = 15, b = 15          覆盖了分支二

 
设计条件覆盖案例时,我们需要考虑判定中的每个条件表达式结果,为了覆盖率达到100%,我们设计了如下的案例:

TestCase1: a = 5, b = 5       true,  true
TestCase4: a = 15, b = 15   false, false


通过上面的例子,我们应该很清楚了判定覆盖和条件覆盖的区别。需要特别注意的是:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false测试到了就OK了。因此,我们可以这样推论:完全的条件覆盖并不能保证完全的判定覆盖。比如上面的例子,假如我设计的案例为:

TestCase1: a = 5, b = 15  true,  false   分支一
TestCase1: a = 15, b = 5  false, true    分支一

 
我们看到,虽然我们完整的做到了条件覆盖,但是我们却没有做到完整的判定覆盖,我们只覆盖了分支一。上面的例子也可以看出,这两种覆盖方式看起来似乎都不咋滴。我们接下来看看第四种覆盖方式。

4. 路径覆盖(PathCoverage)

又称断言覆盖(PredicateCoverage)。它度量了是否函数的每一个分支都被执行了。 这句话也非常好理解,就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合,可想而知,测试路径随着分支的数量指数级别增加。比如下面的测试代码中有两个判定分支:

int foo(int a, int b)
{
    int nReturn = 0;
    if (a < 10)
    {// 分支一
        nReturn += 1;
    }
    if (b < 10)
    {// 分支二
        nReturn += 10;
    }
    return nReturn;
}


对上面的代码,我们分别针对我们前三种覆盖方式来设计测试案例:

a. 语句覆盖

TestCase a = 5, b = 5   nReturn = 11

 语句覆盖率100%

b. 判定覆盖

TestCase1 a = 5,   b = 5     nReturn = 11

TestCase2 a = 15, b = 15   nReturn = 0

判定覆盖率100%

c. 条件覆盖

TestCase1 a = 5,   b = 15   nReturn = 1

TestCase2 a = 15, b = 5     nReturn = 10

条件覆盖率100%

 

我们看到,上面三种覆盖率结果看起来都很酷!都达到了100%!主管可能会非常的开心,但是,让我们再去仔细的看看,上面被测代码中,nReturn的结果一共有四种可能的返回值:0,1,10,11,而我们上面的针对每种覆盖率设计的测试案例只覆盖了部分返回值,因此,可以说使用上面任一覆盖方式,虽然覆盖率达到了100%,但是并没有测试完全。接下来我们来看看针对路径覆盖设计出来的测试案例:

TestCase1 a = 5,    b = 5     nReturn = 0

TestCase2 a = 15,  b = 5     nReturn = 1

TestCase3 a = 5,    b = 15   nReturn = 10

TestCase4 a = 15,  b = 15   nReturn = 11

路径覆盖率100%


太棒了!路径覆盖将所有可能的返回值都测试到了。这也正是它被很多人认为是“最强的覆盖”的原因了。

还有一些其他的覆盖方式,如:循环覆盖(LoopCoverage),它度量是否对循环体执行了零次,一次和多余一次循环。剩下一些其他覆盖方式就不介绍了。

总结

通过上面的学习,我们再回头想想,覆盖率数据到底有多大意义。我总结了如下几个观点,欢迎大家讨论:

a. 覆盖率数据只能代表你测试过哪些代码,不能代表你是否测试好这些代码。(比如上面第一个除零Bug)

b. 不要过于相信覆盖率数据。

c. 不要只拿语句覆盖率(行覆盖率)来考核你的测试人员。

d. 路径覆盖率 > 判定覆盖 > 语句覆盖

e. 测试人员不能盲目追求代码覆盖率,而应该想办法设计更多更好的案例,哪怕多设计出来的案例对覆盖率一点影响也没有。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/591864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【30天熟悉Go语言】4 Go的变量、常量、运算符

文章目录 一、前言二、变量1、变量的基础使用2、变量的多种使用方式1&#xff09;全局变量2&#xff09;局部变量3&#xff09;丢弃赋值 3、Go和Java的变量对比 三、常量1、Go和Java的常量对比 三、运算符1、算术运算符 、--2、运算符 &、* 四、总结 一、前言 Go系列文章&a…

计算机组成原理 之 第四章 指令系统

1. 指令格式 通常包括操作码字段&#xff08;OP&#xff09;和地址码字段&#xff08;A&#xff09;&#xff0c;有的指令不需要地址码 指令系统&#xff08;指令集&#xff09;&#xff1a;一台计算机的所有指令的集合&#xff0c;eg&#xff1a;X86、ARM &#xff08;1&#…

手机安卓Termux搭建Hexo博客网站,发布公网访问

文章目录 1. 安装 Hexo2. 安装cpolar内网穿透3. 公网远程访问4. 固定公网地址 转载自cpolar极点云的文章&#xff1a;安卓手机使用Termux搭建Hexo个人博客网站【内网穿透公网访问】 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章&#…

一键搭建本地Wordpress环境 - MacOS

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

聊聊企业无线网络安全

新钛云服已累计为您分享749篇技术干货 不知不觉无线网络已经成为了办公网主流。最早接触无线网络的时候是2001年&#xff0c;那时候笔记本电脑还比较少见&#xff0c;标配也不支持无线网络&#xff0c;要使用无线网络需要另外加一块PCMIA接口的无线网卡。第一次体验无线网络的时…

【k8s】Jenkins实现springcloud应用CI、CD实践 【三】

一、运行Jenkins流水线流程思路&#xff1a; 场景&#xff1a;java微服务应用&#xff0c; 单体仓库&#xff0c;多个微服务模块&#xff0c;&#xff08;并行构建、自动化构建、根据模块变更仅更新特定模块&#xff09; java、nodejsCI阶段 并行方式; 根据模块变…

【AUTOSAR】Com通讯栈配置说明(三)---- CanSM模块

CanNm模块 该项目中的Nm 并非 autosar nm&#xff0c; 不适用ETAS 配置 CanSM CanSMConfiguration CanSMModeRequestRepetitionMax: 模式请求失败后最大的重试次数 CanSMModeRequestRepetitionTime&#xff1a;模式请求重试时间间隔 CanSMManagerNetworks CanSMBorCounterL1…

数据结构与算法-递归

2.3 递归 概述 定义 计算机科学中&#xff0c;递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集 In computer science, recursion is a method of solving a computational problem where the solution depends on solutions to smaller in…

分享一个下载软件的html

主要是html与js,css实现 页面如下: 点击软件后会滑动到,软件介绍,然后弹出二维码: <!DOCTYPE HTML> <!--HTML for wufuba.comAuthor: www.wufuba.com --> <html lang="zh-cmn-Hans"><head><title>xxx软件</title><m…

Ora提示词版ChatGPT机器人

Ora可以自己创建一个ChatGPT机器人&#xff0c;可以设置自己的提示词例如我创建的AI佛祖https://ora.ai/aesthetic-red-nfa4/ai%E4%BD%9B%E7%A5%96 提示词 创建机器人的时候&#xff0c;需要设定自己的提示词&#xff0c;例如&#xff1a; 假设你是佛祖&#xff0c;名字叫做释迦…

设计模式之~享元模式

定义&#xff1a; 享元模式英文称为“Flyweight Pattern”&#xff0c;又译为羽量级模式或者蝇量级模式。 享元模式&#xff08;Flyweight Pattern&#xff09;主要用于减少创建对象的数量&#xff0c;以减少内存占用和提高性能。这种类型的设计模式属于结构型模式&#xff0c…

git 分支管理:009

1. 分支的(创建、切换、删除) 注意&#xff1a;进行分支操作之前&#xff0c; 需要将当前分支需要提交的文件全部提交&#xff0c; 否则会将未处理的内容一并带到新分支下&#xff0c;这样容易造成分支内容混乱。 查看分支&#xff1a;git branch 创建分支&#xff1a;git bran…

氟化物超标怎么处理

项目基本信息 工艺及产品信息 甲方 / 采用工艺 过滤系统螯合树脂除氟系统 工程公司 / 工艺原理 废水除氟&#xff0c;耐受氯离子、硫酸根等阴离子的干扰 开始时间 2020/11/12 工艺特点 再生周期长 结束时间 2020/11/30 型号 CH-87 项目周期及项目地 15天 江…

力扣高频SQL50题(基础版)——第一天

力扣高频SQL50题(基础版)——第一天 1 可回收且低脂的产品 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # WHERE子句中使用多条件 SELECT product_id FROM Products WHERE low_fatsY AND recyclableY1.3 运行截图 2 寻找用户推荐人 2.1 题目内容…

多家快递如何同时跟踪物流信息并分析出问题件

在这个快节奏的时代&#xff0c;我们经常需要查询快递信息&#xff0c;但是传统的快递查询方式可能需要花费大量的时间和精力。那么&#xff0c;有没有一种更加高效的方法可以同时分析多家快递物流信息并分析出问题呢&#xff1f;答案是肯定的&#xff01;快递批量查询高手应运…

Latex

Latex 文章目录 Latex安装VSCode 配置 latexReference 安装 sudo apt-get install texlive-full # 安装时间有点长,其中的xetex集成了中文字体的环境&#xff0c;使得中文文档的生成变得很容易&#xff0c;可以使用系统自带得字体&#xff0c;使用更好看得字体。 apt-cache se…

Django实现接口自动化平台(三)实现注册功能【持续更新中】

上一章&#xff1a; Django实现接口自动化平台&#xff08;二&#xff09;认证&授权&登录【持续更新中】_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 一、背景 1.1 实现功能 1、一共提供三个接口&#xff1a; 使用Django 自带的User模型&#xff0c;实现注…

《计算机组成原理》唐朔飞 第7章 指令系统 - 学习笔记

写在前面的话&#xff1a;此系列文章为笔者学习计算机组成原理时的个人笔记&#xff0c;分享出来与大家学习交流。使用教材为唐朔飞第3版&#xff0c;笔记目录大体与教材相同。 网课 计算机组成原理&#xff08;哈工大刘宏伟&#xff09;135讲&#xff08;全&#xff09;高清_…

ChatGPT是什么,一文读懂ChatGPT

ChatGPT是个啥&#xff1f; 近期很多朋友后台私信GPT如何访问&#xff0c;我在网上找到一个免梯子的GPT&#xff0c;使用起来还是挺顺畅的&#xff0c;有需要的可以尝试使用&#xff0c;传送门&#xff0c;界面也挺清新的 近期&#xff0c;OpenAI 发布了 ChatGPT&#xff0c;是…

【JavaSE】Java基础语法(三十八):并发工具类

文章目录 1. Hashtable2. ConcurrentHashMap基本使用3. ConcurrentHashMap1.7原理4. ConcurrentHashMap1.8原理5. CountDownLatch6. Semaphore 1. Hashtable Hashtable出现的原因 : 在集合类中HashMap是比较常用的集合对象&#xff0c;但是HashMap是线程不安全的(多线程环境下…