2.1 单元测试应该谁来写?

GreyZeng 2021-07-23 10:07:02

在《构建之法》第二章,对于单元测试,有这样一段描述:

单元测试必须由最熟悉代码的人(程序的作者)来写。
代码的作者最了解代码的目的,特点和实现的局限性。所以,写单元测试没有比作者更适合的人选了。

从我目前的经验和经历来看,假如我作为某个事物(不一定是代码)的作者,自己找自己的错误往往会有一种“我没有问题”的心理暗示,而帮别人做一些检查(也不一定是代码)时,因为自己相对作者来说是一个“傻子”,可能都没有理解他搞这个要做什么,所以更容易去给出一些作者从来没有考虑过的“用例”。“当局者迷,旁观者清”大概是这个道理吧。

最近我在一项工作上面临其他同学的检查,在这个期间我们工作小组共同完成的工作被其他组的同学谨慎检查后提出了几十个问题。我个人的体会是,因为我自己预先在心里给这个事情的前提条件设定了一些“期望”,而这些“期望”并不为其他人所知,所以其他人更能 hack 我。

我认为这种检查,和写单元测试属于一类事情,应该拥有类似的经验教训可以吸取,所以我目前觉得单元测试未必要交完全交给最熟悉代码的人来写。熟悉代码的人,比如作者,尽可能地去覆盖自己现有的路径;其他不太熟悉代码的人,可以在原有的单元测试上做补充工作,这些人由于有一个学习的过程,所以思路不是纯白盒测试,而是“从黑逐渐到白”盒测试,这样容易发现诸如原有代码的路径划分过于“粗糙”的一些问题。
————————————————
版权声明:本文为CSDN博主「战晨曦-18373466」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/BUAA_Wander/article/details/123433306

...全文
919 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
GreyZeng 2023-07-15
  • 打赏
  • 举报
回复

我认为单元测试由谁来做应该具体情况具体分析。开发人员和专门测试人员来负责各自有优缺点:

开发人员做单元测试:
优点:开发人员对代码最熟悉,而且开发人员编程技能相对比较强,所以开发人员自己写单元测试效率上和覆盖率上都比较高
缺点:开发人员平时写业务代码就要花费很多时间,有时候确实没有时间写单元测试;而且大部分开发人员没有太好的测试思想,单元测试可能只是写个最简单的用例就完了;自己写的代码自己测,往往都是不靠谱!
测试人员做单元测试:
优点:测试人员有比较系统的测试思想,可以更好地保证用例的覆盖。而且通过写单测测试能更好地了解具体代码结构、流程,对于后续的业务测试也非常有利。
缺点:测试人员的编程技能相对比较弱,如果不同编程是无法开展单元测试的。并且测试人员对代码没有开发人员熟悉,效率会比较低。

————————————————
版权声明:本文为CSDN博主「_湫_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_57687900/article/details/129209881

GreyZeng 2022-06-29
  • 打赏
  • 举报
回复

在我们的团队中有一个专门负责测试的同学,我认为由于在经过团队会议后,所有人对需求的理解应该都是相同的,不存在我之前所想的两个人对功能需求理解不同的情况,因此我认为这个由测试的同学来写也是比较合理,当然,在代码移交给测试的同学前,这个功能已经被写代码的同学测试了很多次了。

原文地址

GreyZeng 2022-06-29
  • 打赏
  • 举报
回复

结对编程中的两个事件可以一定程度上解答该问题:

  1. 命令行参数的错误处理部分是由潘佬完成的,单元测试则是由我来编写的。这个过程某种程度上相当于一种独特的「代码复审」,我们在这个过程中对题目的描述的理解更加明确,并在这个基础上对相关 bug 进行了修复。这说明了由程序作者之外的人去进行单元测试是非常可行也是很有益处的。

  2. 单词去重部分的逻辑是由我来完成的,而求解单词环相关的单元测试也是由来我编写的。在两种情况中我没有对单词去重,而后续逻辑会导致结果中出现相同的单词,但我阅读题目的过程中理解出现了偏差,认为这种情况是可以出现单词重复的,所以完全忽视了相关的单元测试,幸亏 DDL 前在潘佬的提醒下我发现了这个 bug,最终将其修复。这说明了如果只由程序作者去写单元测试,因为编写者囿于自己的逻辑,会导致一些简单到离谱的 bug 根本测不出来。

由此可得,在本学期结对编程这种「需求描述复杂度远高于代码编写难度」的项目中,由非程序作者来编写单元测试是非常重要的。当然,正如我在提问时所写,并不是说程序作者就不需要编写了,对于以「代码编写难度」为主的项目,其他人很难对相关细节进行针对性测试,这时程序作者亲自编写单元测试仍是不可替代的。

原文地址

GreyZeng 2022-06-29
  • 打赏
  • 举报
回复

在团队项目中,我了解到单元测试只是测试的一方面,且由于需要对每个模块设计单元测试。因此由写代码的人亲自实现在效率上会更高。而测试人员则可以负责更多其它黑盒白盒测试等内容。

原文地址

GreyZeng 2022-06-29
  • 打赏
  • 举报
回复

学期初我的想法是:单元测试同时应该由模块的设计者进行,因为他们对于整体功能有清晰的把握,能克服个人理解代码的局限性。而在本学期结队项目与团队项目的实践中,我对于单元测试的作用又有了新的理解:

结队项目阶段:这是本学期敏捷软工比较艰难的时期,由于需求说明书的复杂性,在做单元测试时仅靠个人的力量是很难覆盖所有情况的,因此通过Issue区的线上讨论与组内的线下讨论,不断丰富测试用例与覆盖率,才能通过强测。

团队项目阶段:后端的情况我并没有深入了解,但应该是达到了课程组的要求;而前端部分虽然有诸如Mocha、Jest这样的测试框架(我们使用的React默认集成了Jest),但不同小组都心照不宣地没有做前端的单元测试。

为此,也许可以从敏捷开发的工作流程中做一些“辩护”:后端理想的开发流程是TDD(Test-Driven Development)的,因此通常要求达到90%以上的单元测试覆盖率,从而保证每一次迭代都处于预料之中;而前端则更接近于BDD(Behavior-Driven Development),注重对行为以及某个具体需求进行测试,前端的单元测试也是近几年伴随着Web应用复杂度的提高而兴起的。

在我们实际的开发中,一方面我们开发的Web应用是单页面应用,整体并不复杂,RD的每一次浏览都是在验证前端行为与代码的正确性;另一方面,观隅前端开发的掣肘在于React陡峭的学习曲线以及由此带来的一系列人力紧缺问题,很多时候由于中英文资料较少,框架本身迭代快,往往需要花费比预期更多的时间,在一次次的失败中摸索出某个具体问题的最佳实践。因此最后前端的测试做得并不好。

说到这里看上去有些跑题,但其实答案早已明确:如果条件允许,单元测试当然是越多越好,除了代码的编写者进行测试,也由模块的设计者等进行测试。而伴随着前端业务逻辑复杂度的提升,为了防止代码自身的劣化与成为重构的绊脚石,单元测试也是必须的。

原文地址

GreyZeng 2022-06-29
  • 打赏
  • 举报
回复

在自己写完代码之后,会最熟悉自己的代码实现的逻辑,知道在编写代码时考虑的情况,对这些情况进行各种测试,在首先保证了自己所负责的部分或考虑到的情况进行充分的测试之后再交给下一阶段的人进行进一步的测试,这样有效提高代码的质量。通过和助教进行交流以及自己在团队项目中对自己的代码进行验证得知写代码的人做单元测试的必要性。

原文地址

GreyZeng 2022-06-29
  • 打赏
  • 举报
回复

经过结对项目以及团队项目的训练,我的结论是:单元测试应该由最熟悉这部分代码的人来写,且这个人有责任尽可能地提高对这份代码测试的覆盖率,不能随便测测拉倒。

在团队开发的时候,虽然我们团队有兼职测试的同学,但是我们不能总是指望把这部分工作交给他来做,毕竟我们团队的这位同学也有相当多自己的开发、运维和压测等更重要的任务要做。能够通过自己单元测试发现的问题,就尽量不要再麻烦管测试的同学,不然来回交流反馈 bug 会降低效率,且在 scrum meeting 或者 code review 的时候被反馈自己所写的代码存在低级的质量问题,也是挺尴尬的一件事情。

在经过几次熬夜修 bug 之后,我亲身体会到在写单元测试的时候,一定要想办法提高覆盖率,并且单元测试所检查的后置条件一定要写得细致一些,而要做到这一点则最好让最熟悉代码的同学来写。我印象比较深的一个 bug 是:有一个 API 需要返回所有未过期或者没有给定期限的 Offer 对象,我在最开始单元测试的时候对这个 API 只写了一个测试方法,该测试方法先在测试数据库中插入 3 个 Offer 对象,这 3 个分别是已过期、未过期以及没有指定日期的 Offer,而我在测试的时候只测试了返回回来的 Offer 个数是不是 2,相信细心的读者会发现,即使 API 判断过期的条件写反了,返回的也是 2 个 Offer(过期的 Offer 以及没指定过期时间的 Offer),而我确实把 API 中这个判断条件写反了。由于判断过期相关的字段的 default 值是 null,且最开始我们创建的 Offer 都没有指定该值,所以线上版本上大部分 Offer 是可以被返回的,但后期我们新加的指定了过期时间 due 的 Offer 却没法被返回,该 bug 直到后期才被细心的队友发现指出,还好修复该 bug 只需要我修改后端代码,不需要改前端,否则可能会严重影响小程序端的使用。经历过这次之后,我觉得自己再也不敢对自己所写模块的单元测试掉以轻心了。
————————————————
版权声明:本文为CSDN博主「战晨曦-18373466」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/BUAA_Wander/article/details/125461867

GreyZeng 2022-03-25
  • 打赏
  • 举报
回复

因为有单元测试覆盖率的要求,所以几乎不会出现 ‘没有意识到问题’ 的情况。 至少能保证 "写了的代码能够被覆盖". 如果模块中缺少某些逻辑+代码, 那么其他人的意见是有可能帮助作者发现这些问题的。

原文地址

GreyZeng 2022-03-18
  • 打赏
  • 举报
回复

我现在已经十分认同作者的观点“单元测试必须由最熟悉代码的人(程序的作者)来写。理由除了作者说的”代码的作者最了解代码的目的、特点和实现的局限性。“之外,我在最近的实现中还学习到测试驱动的开发(TDD)的优越性,在这种开发模式下,也只能是开发人员写自己的单元测试,而且是先于开发的代码。

至于我之前提到的疑问“自己的错误和缺点往往很难由自己发现”,这么说是正确的,这也是我们需要专门的测试人员的原因,但单元测试的目的是保证开发人员写的函数按照他的想法正常运行,不出现明显的bug。就像作者说的“单元测试不能解决所有的问题,不必期望它能发现所有的缺陷”。我还提出“开发人员同时作为测试人员既越俎代庖又效率底下”。经过我的实践,我现在的感觉恰好相反,认为测试人员写开发人员测单元测试才是越俎代庖、效率低下。在一次项目实践中,由于开发进度比较赶,一直没有做单元测试,直到后来有了时间,需要统一补齐之前的单元测试。我补的函数有些是自己写的,有些是其他人写的。给其他人写的函数做单元测试是一件痛苦的事情,你需要先了解他函数的企图和细节,如果开发人员本身水平和代码风格有问题的话,常常写一个函数就要花大量的时间,有时还需要找到底是谁写的这个函数,当面去问问清楚。可见,如果单元测试交付给专门的测试人员去写,而不是开发人员写,效率会有多低下。

原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

​ 在结对项目构造单元测试和团队项目完成后端接口的单元测试过程中我对这一问题有了更加深入的理解。结对项目中我和另一位同学交叉构造单元测试样例,即接口和单元测试不由同一人编写;而在团队项目中,我一人负责与数据库相关的各接口的编写和单元测试的构造,即接口和单元测试是由同一人编写。通过实践我发现,这两种方式都能达到较好的效果,即无论开发人员是否负责自己模块的单元测试编写都不会造成需求上的理解问题。回顾结对项目和团队项目过程,我发现我编写代码时往往是从逻辑的角度对需求进行拆分,安排具体的 if 块等;而在编写单元测试时我往往无脑对着需求构造样例,二者是完全不同的思考方式和行为习惯,我认为,此即单元测试的优势所在,也是在实际开发过程中不需要开发人员交叉单元测试的原因所在。
原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

当局者迷,旁观者清。如果让一个并不熟悉这一部分代码的人来编写单元测试,他就有更大的概率突破作者本身的思维定式,而对于一些刁钻的边界情况进行处理,这种边界情况不仅仅包含输入输出内容,还包括调用位置、调用时机等等多个方面。

先说结论:我现在认为,单元测试并不一定需要作者自己写,重要的是对于功能的覆盖程度、对于文档的适应性和错误处理的覆盖面要广,也就是编写测试的人要非常明确自己在测什么、明确自己需要覆盖什么情况,而这种人往往是作者本人

当时@宝玉老师在博客下面的指导在当时就令我大致明白了这个问题的答案:

是不是作者写不过是不同的手段,甚至单元测试本身也是手段。

但是软件工程的方法论不就是讨论通过何种手段达到目的的吗?

对,但是不要错把手段当目的

是的,单元测试无非只是一个保证迭代开发的稳定性、保证处理逻辑的条理性、保证处理范围的广度的一个手段而已,我们做单元测试不是为了达到多少覆盖率而去做测试。类似地,至于是谁作为测试者编写单元测试,那更是实现单元测试的一个手段而已。

不管黑猫白猫,能捉老鼠的就是好猫。

只要手段能够达到目的,则是好手段,要抓的是主要矛盾。至于能否达到目的,需要具体情况具体分析。

很巧,本学期在结对编程和组队项目中,我有幸体验了“测试员”的角色。

结对项目中对于边界情况的要求较多,对于各种特殊情况的处理难以进行全面覆盖性的测试,由于我本人参加过一些算法竞赛,对这方面数据的构造有一定经验,同时担任了驾驶员的角色,因此“单元测试”自然而然的由我进行编写。对于代码的了解和对于样例构造的表格记录,同时在测试时不考虑自己实现的细节而专注于进行全面覆盖性的测试,极大地保证了代码的正确性和鲁棒性,这可能就是作为代码编写者本人进行测试的一个优势所在。

组队项目中,我负责后端的单元测试。组队项目与结对项目中的待测代码可谓天壤之别,大相径庭。组队项目的待测代码主要是没有什么疑问的 API 功能实现,如从数据库中读一些东西返回给前端,前端传来点东西扔进数据库,有极高的重复率;最可能出问题的单词推荐算法部分也大部分是由本人执笔的。因此,我仅对于部分较有代表性的代码进行了覆盖性的单元测试,测试的过程中确实发现了一些实现方面的细节问题;但在仅仅达到 70% 的单元测试覆盖率后,我们在后续操作的测试中就没再发现问题了。

虽然确实如果还有充足的时间,我会尽量将更多的情况进行覆盖性测试,70% 的覆盖率确实有些低了;但是由于需要进行前后端对接、新算法实现以及作为 PM 的团队规划,进行较为全面的覆盖性测试不现实,因此仅仅使用了性价比最高的、忽略重复无意义操作测试的方案;但从此也可以看出,在软件工程中对于目的和手段的主次需要进一步明确

私以为,从这里就可以看出,敏捷开发最关注的可能就是所做事物的性价比。因此,我有一个新的疑问提出:

如果明知一个事情是对的,但是对不对的权利不掌握在你手中(比如老板),而且他执着坚定地、甚至可能先入为主地认为,这个事情并不对。这时,是否应该选择性价比更高的妥协?

我不知道。希望我将来也不需要知道。

原文地址

GreyZeng 2021-07-24
  • 举报
回复
@GreyZeng 回复来自于:https://www.cnblogs.com/Potassium/p/14956247.html#4900128 > 如果明知一个事情是对的,但是对不对的权利不掌握在你手中(比如老板),而且他执着坚定地、甚至可能先入为主地认为,这个事情并不对。这时,是否应该选择性价比更高的妥协? 首先,总会知道的,不必担心。 我也遇到过类似的情况,我的做法是——如果感觉能争取的赢,那就争取;如果感觉还待得下去,或者还有必要一定得待下去,绝对争取不过的话那就妥协,甭管内心保留的意见多大接下来都绝对服从命令;如果感觉待不下去,或者感觉没有带下去的必要,那就干脆果断的及时止损,走为上。 简单得很。
GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

学期初我认为,程序作者本身可能更容易陷入自己的思路,导致忽略一些边界情况。应该是最熟悉需求的人来写单元测试。但是这一想法在软工实践中体现出了其问题:

在团队作业中,针对代码的单元测试,我们尝试了这样的三种方式:由作者本人写、由PM(团队中最熟悉需求的人)写、由完全无关的其他人写。针对这三种情况,我们对应的效率(代码行数×覆盖率÷编写时间)排序为,E作者>EPM>E无关人员。按照我原来的想法,应该是EPM>E作者才对,但是事实与之矛盾,说明我的假设出现了问题。

针对这个结果,我重新修改了假设:对于单元测试的代码,由谁来撰写存在两方面的考虑,一是效率问题,即多久可以完成对代码的单元测试覆盖,随着代码量的增大,对于非作者本人而言的单元测试编写者,效率会成指数级下降,因为需要更多时间去理清代码之间的逻辑;二是覆盖情况问题,即单元测试编写完成后,还有哪些特殊的边界情况未覆盖到,可能PM对用户应用场景更熟悉进而可以更多地覆盖这样的特殊情况,但是软件工程团队作为一个整体,开发人员也应该对需求有一定的了解。因此,基于这两方面的权衡,程序作者在单元测试的编写方面比PM更好。
原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

经过这学期软工课程的学习,对于单元测试也有了更深入的理解。当然,单元测试由代码作者与代码作者之外的人共同参与效果会更好,但在团队项目的实践中,发现其实并没有那么多时间,那么多人手来做测试。这种情况下显然是由代码的作者来写单元测试更为合适,在时间并不充裕的情况下,相对于其他人而言,作者能更快地写出覆盖更全面的单元测试,这也是一种对资源的最大化利用。
原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

当初提出这个问题的时候并没有实际的多人编程经历,所以仅凭自己的臆测提出了这个疑问,现在我认为我能为自己作出一定的解答。

首先,我的答案是最好不要由他人来编写单元测试,理由有二:

  1. 我在结对编程与团队项目中都有过替他人的代码编写单元测试的经历,但感觉并不会对软件的整体质量有什么正面提升。因为如果你要为他人编写单元测试,你就需要知道这个单元的功能,但由于这个功能是从你对源码的阅读中理解来的,可能与编写者的想法有一些出入,这就导致了单元测试可能并不会有很好的覆盖效果,并且不断阅读别人的代码本身也不是一个太好的体验。
  2. 单元测试主要是对一个单元的功能进行检查,也就是说,编写者一开始就要对单元的功能有所了解,然后在编写完后通过单元测试来检查在编写过程中是否有逻辑错误。这也就意味着并不会出现我在当初提问题的时候所提到的”自己跳不出自己的逻辑错误“这种情况。

原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

单元测试确实由程序的作者来写是比较好的。

当时我认为程序作者在编写程序和构建单元测试时思路容易高度一致,从而导致不能够发现问题,达到单元测试的真正作用。但是经过真正的实践之后我发现,我当初的思考过于理想化,不够实际。

首先,程序编写时更加注重的是实现细节,如何去完成这个功能,而编写单元测试时更加注重的是能否得出正确结果,二者的重点不一致也就谈不上具体思路相似的问题;其次,只有熟悉这个程序,熟悉这个功能的人来编写单元测试才能够知道单元测试的边界是什么,具体范围应该是什么,只有清楚知晓这些问题的人,才能够进行较好的单元测试编写工作;最后,编写单元测试也是程序作者的再一次思考,为什么这组数据存在问题?为什么这组数据运行时间较长?从而重新审视当时的实现思路,进行程序的优化,以达到更好的性能。
原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

对于这个问题,笔者的观点没有发生变化——最好还是应该交给专门的测试人员来完成。

不过,在敏捷开发这一场景下,在人力资源捉襟见肘的前提下,那当然还是交给代码的作者比较好——毕竟总好过交给另一个同样还在做其他开发任务的人。

原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

现在我认为编写单元测试的最佳人选确实是代码的作者本人。

单元测试是来测试软件的基本功能是否正确,代码的编写者是对自己编写的代码各部分功能最了解的人。比如在这学期的结对作业中,各个函数中的分支,循环逻辑都是由两个成员协商公共完成的,只有他们两个人对代码的各个部分功能是最熟悉的,熟悉代码中可能出现问题的edge case或者如何构造各个覆盖分支的测试用例。在团队项目中原理也类似。并且代码的作者能够在出现bug后快速定位问题所在位置。

综上所述我认为还是由代码作者编写单元测试更好。

原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

写单元测试确实没有比作者本人更合适的人选了。

首先,单元测试的目的是对代码的基本行为功能进行测试,从这一点上编写代码的作者对代码所需要具备的行为功能最为了解,能够测试到代码行为的方方面面,包括边界,包括异常测试和捕捉,这点也是在我实际编写单元测试中有所体会的(单元测试的覆盖率);

其次,单元测试编写的过程,其实也是对代码进行调整和优化的过程,在编写单元测试的同时,编写者也是再一次审视代码,对于非代码作者而言,他需要重新理解代码的逻辑,如果出现bug可能还需要更长的时间来进行调整,而对于代码作者来说,如果出现bug就能够更快地调整,也能够帮助自己二次梳理自己的逻辑。

原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

对该问题我仍然坚持当初的意见,单元测试由代码的作者或者了解功能定义,测试经验丰富的人编写都是可行的。不过根据结对编程中单元测试的经验,我现在倾向于由代码的作者来编写,尤其是对于小规模团队,因为这样有利于分工和责任分配。如果有了解功能定义,测试经验丰富的人,可以让其做整体的功能测试、压力测试等,以保证产品的宏观质量。
原文地址

GreyZeng 2021-07-24
  • 打赏
  • 举报
回复

经历了团队项目的实践,我对于这个问题的认知有很大的变化。

当时我认为,做好单元测试很重要,最好由他人(而不是程序的作者)编写,因为这样做能在测试的时候尽量做到客观和理性。

但现在我的想法是完全赞同《构建之法》作者的观点。在小型项目中,项目代码量较少,由他人负责单元测试的成本不是很高,这个时候无论是程序的作者还是他人,编写单元测试我认为问题不大。但对于一个大型团队项目,如果由不熟悉代码的人进行单元测试,由于代码规模很大,重新熟悉代码的成本过高,测试需要额外花费大量时间和精力。而对于一个快速开发的项目来说,时间是最宝贵的。另外,由最熟悉代码的人员进行单元测试,由于代码已经具备一定的复杂度和规模,作者不太会局限于之前的思维定势因为之前写的细节都已经不记得了,所以不用担心作者编写单元测试会忽略很多bug的问题。

事实上,在团队项目中,我们都是负责自己代码的单元测试。
原文地址

加载更多回复(3)

605

社区成员

发帖
与我相关
我的任务
社区描述
程序员。写过:移山之道,编程之美,构建之法,智能之门。
软件工程软件构建团队开发 企业社区 北京·朝阳区
社区管理员
  • SoftwareTeacher
  • GreyZeng
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧