提高单元测试覆盖率的意义与价值


什么是单元测试覆盖率 ?

单元测试覆盖率是一种软件测试的度量指标,指在所有功能代码中,完成了单元测试的代码所占的比例。有很多自动化测试框架工具可以提供这一统计数据,其中最基础的计算方式为:

单元测试覆盖率 = 被测代码行数 / 参测代码总行数 * 100%

Note: 一般情况下, 参测代码总行数是指排除配置文件、以及测试代码本身的所有功能代码的总行数。


单元测试的度量方式

最常见的单元测试覆盖率的度量方式有以下三种:

1. 行覆盖率 / 语句覆盖
这种覆盖率统计方式是最为基础的,它可以用于体现参测代码中已被执行和未被执行的代码行(语句),从而可以进一步推断代码的逻辑覆盖是否全面。

2. 分支覆盖
这种覆盖率统计方式是用于统计代码中所有判断分支是否都被覆盖,如

...
if (condition)
{
    Operation_1();
} 
else 
{
    Operation_2();
}
...

语句就会根据 condition 的值产生两个不同的分支操作,那么在统计分支覆盖时,就需要对两个分支都进行校验。值得注意的是,上例中的代码,其分支覆盖可以被行覆盖所取代,也就是说若上面代码的行覆盖率为100%, 则其分支覆盖率亦为100%。

但是如果将代码换为三元表达式,如

...
condition ? Operation_1() : Operation_2();
...

此时,行覆盖率在统计时,只要这一行代码有被执行,那么行覆盖率必然为100%,并不关心是否两种情况都被执行过。但如此一来就没办法通过行覆盖率保证其分支覆盖率为100% 了。

3.条件覆盖
这种覆盖统计方式是针对代码中产生多分支,并且每个分支的激活条件比较复杂的情况。
代码的分支一般都是通过流程控制语句产生的,而流程控制语句再激活一个分支时是需要条件的,依然以之前的代码为例,若condition 是几个布尔值的组合,

...
if (Condition())
{
    Operation_1();
} 
else 
{
    Operation_2();
}
...

private bool Condition () {
  return condition_1 || condition_2 && condition_3;
}

那么此时,代码依然只有两个分支,但是由于激活条件是取决于condition_1, condition_2, condition_3的组合情况,那么在校验条件覆盖时,就应该考虑所有可能的组合情况,也就是8种测试用例。这样才可以使条件覆盖的覆盖率达到100%。全面考虑条件覆盖的做法就可以达到优化测试的效果

其实,覆盖率的统计方式还是用很多其他种类的,这里给出的只是几种最基础的。但不管怎样,完备的单元测试行覆盖都是其他度量方式的基础。当行覆盖率达标之后,开发人员才会有精力修改、优化测试用例,从而提高分支覆盖率、条件覆盖率等其他更具业务价值的单元测试覆盖率。


提高单元测试覆盖率的意义与价值

摘自《TestCoverage》Martin Fowler

有些时候,我们想提高项目测试覆盖率的阈值,比如从45% 提高到80%,又或者从 95% 提高到100%。
那么这个时候,我们就需要问一问自己,为什么要做这样的事情?提高覆盖率的意义与价值何在?

1. 是想通过单元测试来保证代码质量?
单元测试的覆盖率高与代码质量高,二者并没有直接关系,这是因为覆盖率的高低完全是可以“造假”的。一些没有实际业务价值的测试用例因运而生,甚至发生类似 AssertionFreeTesting 的情况,使覆盖率“虚高”
因此,我们没有依据说明高覆盖率就能确保好的代码质量。

2. 是想通过单元测试保证业务逻辑不会出错?
用单元测试保证业务逻辑,看上去很有道理。可是仔细一想,就会发现这一点,其实有些不切实际。一个业务功能的实现并不仅仅依赖于某一个方法、某一个类,那么通过单元测试能够保证的业务逻辑也是十分有限的,不可能做到“不会出错”
可以试想,如果仅仅依靠测试金字塔最底层的单元测试,使其覆盖率达标就能保证业务逻辑不出错,那么为什么还需要更高层的集成测试和功能测试,甚至探索性测试呢?
另一方面,如果是想将单元测试与业务逻辑相绑定,那么方向也不应是提高覆盖率,而应该是提供更加符合业务场景的测试用例给已有的单元测试,也就是提高已有的单元测试质量。

如此一来,这两个问题都无法通过提高单元测试覆盖率解决,那么我们提高覆盖率还有什么意义与价值呢?

测试覆盖率帮助我们找到没有被测试的代码
提高测试覆盖率,可以让我们在重构、优化这些没有被测试的代码时更有底气

但是,最大的前提是你的测试代码是值得信任的

那么现在,我们可以考虑一下这两种情况了:

  1. 将覆盖率从 45% 提高到 80%。
  2. 将覆盖率从 95% 提高到100%。

对于第一种情况,不到一般的初始测试覆盖率而言,首先会让开发人员在进行重构时很没有安全感,由于未被测试覆盖的代码量太多,从而无法快速发现改动是否会对未覆盖的代码带来不良影响。 因此,在这种情况下,提高代码的覆盖率,从而让更多的代码被测试,让开发者在重构时能更放心,这对项目更有益。

而对于第二种情况,可以看到覆盖率已经很高了,那么这个时候,
首先看看开发者经常改动或重构的代码是否都被覆盖,如果是,则重点应该放在优化测试用例上,看看是否所有的边界条件都被测试,所有的分支都被覆盖等等。因为这时,提高已有的单元测试质量,让测试用例更贴近业务场景所带来的收益会远远大于进一步提高测试覆盖率所带来的收益。
否则,一旦重构了未被覆盖的参测代码,就应该为改代码添加单元测试,使之被覆盖,从而确保功能的正常运作。


总结

  1. 单元测试仅用来保证代码所对应的功能正常,若想将之与业务结合,需要贴合业务场景的测试用例。
  2. 单元测试覆盖率仅用来找出未被测试的代码,若想通过覆盖率保证业务逻辑,需要进一步优化已有单元测试的质量。
  3. 提高单元测试覆盖率仅对之前没有测试覆盖或覆盖极其不足的代码有显著增益,若想对已经被测试高度覆盖的代码进行优化,需要着眼于提升已有的测试用例质量。
  4. 团队合作开发,应尽量保证自己每次提交的代码都已经全部被测试覆盖

参考文章

TestCoverage
AssertionFreeTesting
单元测试之覆盖率浅谈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 1.测试与软件模型 软件开发生命周期模型指的是软件开发全过程、活动和任务的结构性框架。软件项目的开发包括:需求、设...
    宇文臭臭阅读 6,664评论 5 100
  • 1.测试与软件模型 软件开发生命周期模型指的是软件开发全过程、活动和任务的结构性框架。软件项目的开发包括:需求、设...
    Mr希灵阅读 21,836评论 7 277
  • 测试现在被普遍认为“保证产品质量”这个笼统的说法下,而测试本身是什么呢?今天我们就测试本身跟大家一起讨论。 测试是...
    西边人阅读 4,442评论 2 52
  • 文章来自:http://blog.csdn.net/mj813/article/details/52451355 ...
    好大一只鹏阅读 9,158评论 2 126
  • 第115篇 《五月抒怀》 一别家乡有数日,满口佳肴味还留; 念念不忘父母情,苦口婆心劝儿悠。 每逢夜来倍寂寥,远望...
    好郝说话阅读 170评论 0 2