为什么要单元测试

简介: 刹?是降低了?速还是提升了?速?我们通常认为写单测费?耗时、耽误研发进度,仿佛在给项?“踩刹?”。?家不妨带着这个问题往下看,详细聊聊为什么单元测试可以让软件开发跑得更快。

2000元阿里云代金券免费领取,2核4G云服务器仅664元/3年,新老用户都有优惠,立即抢购>>>


阿里云采购季(云主机223元/3年)活动入口:请点击进入>>>,


阿里云学生服务器(9.5元/月)购买入口:请点击进入>>>,

什么是单元测试
?家对于单测应该并不陌?,截取?段维基百科的定义帮?家唤醒?下记忆:
在计算机编程中,单元测试(Unit Testing)?称为模块测试,是针对程序模块(软件设计的最?单位)来进?正确性检验的测试?作。
单元测试的理念其实?直是编程的?部分。我们第?次编写计算机程序时,肯定会输??些样本数据,查看其是否按照你的期望执?。如果结果不符合预期,你肯定在代码?穿插过?量的System.out.println,确保每个原?节点都符合预期。这个过程其实就是把复杂问题拆解成原?化的问题、逐?攻破的过程。单元测试的?的也?样,是保障软件程序中每个最?单位的正确性,从?保障由最?单位构建起来的复杂系统的正确性。
深?展开单元测试的必要性之前,我们先去考考古,看?下测试体系是如何演进的。
测试体系的演进
image.png
过去的很??段时间?,软件测试?量依赖??检测。软件测试甚?是?个独?的?种(QA、Tester),QA/tester的?常任务就是进??量的??测试、繁琐易错。
?2000年代初以来,软件?业的测试?法已经发?了巨?的变化。为了应对现代软件系统的规模和复杂性,业界演变出了开发?员驱动的?动化测试实践。我们终于可以摆脱?动测试的繁琐,?软件来测试软件。但过去的实践仍然留下了深远的影响,软件测试还是?个独?的?种,过去的QA演进成了SDET(Software Developer Engineer in Test),我们虽然进化到会使??具了,但我们还只是会??具的猴?。为什么这么讲?因为这种研发/测试分离的模式本身就留下了很多问题。当研发和测试是两个岗位时,交付的边界是软件整体的功能性(functional requirements)和可?性。研发只要保证软件整体上功能完备、可?就?,测试也会聚焦在集成测试和端到端测试上。但软件是由?数个最?单位构成的,在这种体系下?们会忽视最?单位的质量、是否可读可测可演进,最终难免“??其外,败絮其中”。
基于种种弊端,?歌、微软这些对研发质量?常重视的公司都在从SDET的2.0时代过渡到 all-in-one 的3.0时代:微软在2015年去掉SDET?种,在陆奇带领的Bing中率先提出“combined engineering” 的概念;?歌也将SETI替换成EngProd(Engineering Productivity),专?负责测试平台和?具的搭建,不负责具体的业务逻辑测试。
# 为什么需要单元测试
在如今的互联?时代,软件迭代的速度越来越快,研发的职责也越来越多。DevOps的理念是"you build it, you run it",研发/测试合?为?的趋势也可以理解为对"you build it, you test it"的呼吁。当研发要对??写的代码质量和测试负责的时候,好的测试实践就必不可少了。
测试?字塔
就像盖楼需要从打地基、竖钢筋、灌?泥层层往上构建?样,测试也有类似的测试?字塔架构。下图出?《Software Engineering at Google》的测试章节,总结了Google在测试??的最佳实践。我们可以看到测试?字塔由三层构成,最底层就是单元测试、占?80%,是软件系统的地基。再往上是集成测试和端到端测试,分别占15%和5%。因为从下往上占?逐层缩减,因此被称为测试?字塔(跟盖?楼?样)。?歌推荐的这个?例是多年实践出来的结果,意在提升研发的效率(productivity)并提升对产品的信?(product confidence)。
测试?字塔的核?理念之?就是“Unit Test First“,每个软件项??的第??测试应该是单测(TDD甚?认为第??代码就应该是单测),?且?个项??占?最?的测试也应该是单测。image.png
优秀的软件离不开单元测试
为什么业界都把单元测试放在这么重要的位置?“抓?放?”,只写端到端测试不?吗?这?我们来展开讲讲单测的好处。
提升debug效率
单元测试是软件?程极佳的地基,因为它们快速、稳定,并且极?地缩?了问题范围,提升故障诊断的效率。
测试更快:单测没有其他外部依赖,跑的快,可以提供更快的反馈环,更快的发现并修复问题。
测试更稳定:同样因为0依赖,单测相?于其他类型的测试更稳定,不会受外部其他模块的不兼容变更影响。因此单测也是最能带给开发者信?的测试类型。
问题更容易定位:单测以最?软件单位为边界,出了问题可以缩?定位范围。相?之下,越是?字塔上层的测试类型,定位问题的困难度越?。复杂的端到端测试涉及众多的模块,需要??排查定位问题。

提升代码质量

代码是写给?看的,好的代码应该是易读、易改、易维护的。写单测的过程其实就是吃??代码狗粮(dogfood)的过程,从?户/研发视?去使???的代码,帮助我们提升代码质量。
好的代码是易测的:业界很早就提出了圈复杂度(Cyclomatic complexity)的概念,?来衡量?个模块判定结构的复杂程度,其数量上表现为独?路径的条数,也可理解为覆盖所有的可能情况最少使?的测试?例个数。圈复杂度?说明程序代码的判断逻辑复杂,可能质量低,且难于测试和维护。因此好的代码?定是圈复杂度低的,也是易于测试的。
易于迭代演进:没有什么软件是?成不变的,好的软件系统应该是易于演进的。单测覆盖?的项?模块更原?化,边界更清晰,修改起来更容易。单测覆盖更全的项?重构的?险也相对更?,相反?个没有单测覆盖的复杂项?是没?敢碰的。
更优质的设计:前?也提到,好的单测能够提升代码的质量。如果?个研发需要给??的代码写单测,他就会注重代码的模块化分割,减少过?、圈复杂度过?的method。下?的例?就是?段没有单测的代码的认知复杂度值(可以理解是圈复杂度的?个改良版,从代码是否容易理解的?度衡量),超标了??三倍。现在回过头来想补单测,脑袋都?。image.png
提升总体研发效率

磨?不误砍柴?,?质量、完善的单测可以提升研发质量和效率,加快项?总体交付速度。这句话乍?看是反常识的,写单测往往?写实现逻辑要更耗时,怎么还能提?效率?这也是?家不写单测最常?的理由:“项?赶进度,来不及写单测”。如果我们的项??命周期是以?计算的,写个原型很快就下线了,那写单测的确ROI不?。但阿?有很多to B的业务,提供给?户的能?都是以年计算?命周期的,?质量代码的ROI随着时间推移会越来越?,具体体现在以下??:

减少debug时间:上?提到种种提升debug效率的原因,这?不再重复。???更?的单测覆盖可以节省debug所花费的时间,另???有充?测试覆盖的项?本身bug数量就会更少。举个现实中的例?:某团队由于历史上?的种种债务,基本全靠端到端测试,毫?单元测试覆盖。造成的后果也?常严重,团队oncall的同学 > 50%的时间都是在修复各种奇怪的bug,没法投?宝贵的精?到架构升级等?期更重要的项?上。
增加代码变更的信?:前?提到没有测试覆盖的代码没?敢碰,有充?单测覆盖的代码可以显著提升改造代码的信?和意愿。再给?家举个例?:我加?阿?之前在Google总部?作过将近?年。如果你在Google?作过就会发现,你的代码经常会收到毫不相关团队成员发起的code change。?多数情况下这些都是同学们?发的去做??积重构(mass refactor),?如看你的Java代码没有?Builder模式,就会帮你做个重构(Google?有?量?动化?具简化这些重构?作)。我们抛开主观意愿不谈,如果是没有测试覆盖的代码、还是毫不相关组的,你敢这么重构吗?我们都希望能有像?歌那样整洁的代码,但没?敢碰的代码怎么变得更好?
提升代码?解释性:?档能够提升代码的?解释性,让研发效率更?。好的单测其实也可以被看作代码的?档,通过读测试就能快速理解代码的作?(参?TDD)。单测作为?档同时还完美的解决了?档保鲜的难题,给开发者提供了?套?质量、随着代码不断更新的?档。
更?效的code review:不是所有的问题和设计上的缺陷都能通过静态检查发现,这也是为什么需要??code review作为代码质量的最后?道防线。在Google,代码评审是代码合并最重要的?个环节,因此评审的效率直接影响总体的研发效率。好的单测覆盖能够减轻评审?的负担,让他们把精?投?到更重要的部分(?如代码设计)。
更频繁的发版:敏捷开发倡导的持续集成、持续部署的前提就是全?、?质量的?动化测试。敏捷开发对于研发的提效就不多展开了。但光是能够更快速的发版本身就已经?常有价值了。

反?模式和常?误区
上?提到了写单元测试的种种好处和业界的最佳实践。我们也列举?下常?的反?模式和误区,帮助?家更好的规避类似错误。
测试的反?模式(anti-pattern)

反?模式?:冰激凌筒模式

只关注?户视?的端到端测试、?量依赖QA测试都会产?如下图所示的反?模式。很不幸,这也是在过去的测试体系影响下最常?的模式。冰激凌筒模式下,测试套件通常运?缓慢、不可靠、难以使?。缺失底层的单测也会让项?变得?常难维护,很难做?的改动。

image.png
反?模式?:沙漏模式

沙漏模式下,项?中有?量的单元测试和端到端测试,但缺乏集成测试。虽然它不像冰激凌筒那么糟糕,但仍会导致许多端到端测试失败,这些失败本可以通过?套中等范围的测试更快更容易地捕捉到。当模块间紧密耦合,使得依赖项很难单独实例化出来的时候,就会出现沙漏模式。image.png

测试的常?误区
常?误区?:?户第?,测试覆盖?户的需求?够了
这个误区下会认为,端到端测试是站在?户视?做测试,把?户要的功能点都覆盖到就?够了。这种误区导致的结果就是冰激凌筒反?模式。虽然软件交付的最终功能是给客户使?的,但构成软件的代码本身是给?(研发)读的、需要?去维护。外部?户是?,内部?户也是?。
常?误区?:All-in端到端测试,节省了80%的测试代码量,赢麻了
从短期来看,不写单测可以节省80%的测试代码量和?少50%的研发时间。但只要项?复杂起来,时间线拉?,过去?的历史债务(technical debt)早晚要加倍奉还。等到真正需要还债的时候再去补,可能为时已晚。
常?误区三:写单测的?都弱爆了,我?这么?还没写出过bug
这篇?章可能不适合你。不过软件开发是个团队项?,你写的代码最终也会落到别???去升级维护,没有测试覆盖的代码是没?敢碰的。

总结

结尾处再快速总结?下。本?从测试体系的历史??,讲述了从?动测试 -> 靠别??动化测试 -> 靠???动化测试的历史演化进程,也尝试着从这个视?解释为什么?家过去不重视单元测试。之后我们分别讲述了什么是单元测试,业界的?字塔测试最佳实践,并且深?讲解了单元测试的种种好处。最后我们列举了常?的反?模式和误区,帮助?家快速识别规避常?的错误。
如果把测试体系的演进类?为?类的进化,那么我认为?单测覆盖和有充分单测覆盖的软件就好?爬?的古猿和直???的现代?类。由衷希望?家能够重视单元测试、写好单元测试,让我们的软件尽快从爬?进化成奔跑,迸发出源源不断的?命?、创造出更多价值!

参考资料:
[1]https://abseil.io/resources/swe-book/html/ch11.html https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html
[2]https://arstechnica.com/information-technology/2014/08/how-microsoft-dragged-itsdevelopment-practices-into-the-21st-century/4/
[3]https://medium.com/nerd-for-tech/the-paradigm-shifts-going-from-1-1-to-10-1-to-100-1-dev-testratio-44183a734d77
[4]https://blog.testproject.io/2018/11/06/the-software-engineer-in-test/

相关文章
|
4天前
|
测试技术
|
11月前
|
测试技术 编译器 Linux
浅谈c++单元测试
浅谈c++单元测试
|
Java 测试技术
单元测试的正确姿势
软件测试是软件质量保证的关键步骤。越早发现软件中存在的问题,修复问题的成本就越低,软件质量也就越高,软件发布后的维护费用越低。为了能更好的保障软件质量,制定统一的系统自测指南,形成统一的流程达到此目标。
309 0
单元测试的正确姿势
|
Java 中间件 测试技术
单元测试都不做,怪不得你没有女朋友
单元测试都不做,怪不得你没有女朋友
单元测试都不做,怪不得你没有女朋友
|
Java 测试技术 容器
还在手动写单元测试?
还在手动写单元测试?
88 0
|
敏捷开发 测试技术 程序员
|
测试技术 C++ 编译器
|
SQL 测试技术 数据库
什么是单元测试?为什么要做?
什么是UT? UT(Unit Test)即单元测试
275 0
什么是单元测试?为什么要做?
|
数据可视化 测试技术 Go
使用 Gomock 进行单元测试
在实际项目中,需要进行单元测试的时候。却往往发现有一大堆依赖项。这时候就是 Gomock 大显身手的时候了 Gomock 是 Go 语言的一个 mock 框架,官方的那种 安装 1$ go get -u github.
4171 0
http://www.vxiaotou.com