测试驱动开发TDD,想说爱你不容易 | 第4期

2022-12-09 17:55:00
践行者
原创
878
摘要:《践行者》第4期,我们邀请了这家公司的CEO——瀚诚软件CEO朱万友老师,和我们一起揭开“测试驱动开发”的神秘面纱。



竟然有这样一家公司,不会测试驱动开发(TDD)就进不去?测试驱动开发究竟有什么神奇魔力,能让这家公司如此“倔强”?《践行者》第4期,我们邀请了这家公司的CEO——瀚诚软件CEO朱万友老师,和我们一起揭开“测试驱动开发”的神秘面纱。


上述问题的答案都在直播回放中啦,快来跟我们回顾一下!

一、《践行者》系列直播回放


《践行者》是一档主打实战落地的访谈栏目,旨在通过对研发实践、项目管理实践践行者的访谈,帮助大家了解到项目管理的实践及其实际应用场景;通过践行者本人的心路历程向大家展示更加生动真实的实践落地过程。

二、测试驱动开发,想说爱你不容易


朱万友老师强调,作为极限编程中的一个工程实践,测试驱动开发(TDD)能够帮助我们写出更健壮的代码。那什么是测试驱动开发?也就是通过先写测试代码或测试用例,定义出“什么是完成”,再快速地进行开发,也就是通过测试来驱动整个开发过程。

测试驱动开发的优势在于极大地改善了软件的设计,让设计达到“够好即可”,同时,站在业务的角度,它也能够帮助团队更好地响应新的需求。另一方面,测试驱动开发让我们得到了非常完善的自动化测试套件,能够帮助我们做回归测试,缩短特性响应时间。

随后,朱老师又对“为什么选择做测试驱动开发”这一话题做出了详细的分享,想了解这一部分的小伙伴可以观看直播回放~

三、访谈实录


对于“测试驱动开发”这一话题,大家也有不少问题希望一同探讨,本期直播的评论区可谓热闹非凡呀~朱老师对大家的问题进行了详细解答,此次我们也将问答环节的所有问题整理出来了,方便大家查阅~

Q1:公司是做什么业务的呀?

A: 我们公司叫瀚诚软件,主要就是帮我们的客户做交付的。其实我们就是一群专业的程序员,为客户做全定制化的软件开发,提供交付服务,当然也会做XP等敏捷咨询。

Q2:测试用例一堆Bug怎么办?

A: 这类问题在测试用例撰写和产品代码撰写是两拨人的团队中会比较突出,在实行TDD的团队应该不存在这类问题。因为TDD是开发者测试,它不是一个专门的测试团队去做测试。测试用例应该由开发者参与撰写的,或开发者写测试用例的同时,QA、BA 这些角色会提供大量支持。所以“测试用例一堆Bug”一般在TDD团队里面不是一个问题。

Q3:一个大型项目,只有PO了解所有功能,成员开发只知道自己提供什么接口,如何分配写TDD?

A: 软件开发并不是让我们直接就上手去写代码。实际上我们在编码前和编码后还有很多工作是要去做的。

拿敏捷团队来说,我们会领到的任务通常是User Story,而TDD就是依据这个User Story去做的。如果User Story将验收标准写清楚,这时我们可以开始对这张Use Story编码,去做任务分解,先写测试,再写产品代码。所以我们应该先把需求拆分明确,再谈如何写TDD,因为TDD只是针对一个Story层面。

在工作中,我们要更好地去完成任务,并不是一个增加和统仓式的这种组织方式,所以我们在讨论需求的时候是一块讨论的,不可能只需要告诉开发接口就可以了。其他的什么都不知道,这样我们就没有办法一起好好工作了。

我们首先要保证团队成员都参与到项目中,这是我们谈TDD的一个大的前提,不论Scrum还是其他的合作形式,都是为了保证我们有良好的沟通。

Q4:如何保证老测试脚本可以一直跑得通?

A: 我们做TDD也好,做自动化测试也好,保证老的测试脚本可以一直跑通是一个基本前提。如果我们做了自动化测试,但会出现随机失败或隔段时间就会失败,那么这样自动化测试就失去了它的价值。

我们在第一天应该要保证所有的测试是能够跑得通的。后续新加入的测试,因为都有前序的自动化测试做保障,我们也能保证新加入的测试也是正确的。

还有一个比较好的解决方案,就是自动化测试或TDD测试套件应时刻去跑。如果这些测试我们时刻去跑、去运行,有错误就会第一时间被发现,这样我们就可以第一时间去修复它。会变得一直可以跑得通。而这不仅是个技术问题,也是一个管理问题。我们的团队要有这样一个团队公约,当测试一旦失败,就立即修复它。通过持续集成这种方式,再加上一些管理上面的纪律,是可以保障测试能一直跑得通的。

另外测试代码应尽量把外部的变化隔离开,比如我们会增加打桩或其他模拟方式,把一些时效的情况随时间变化模拟出来。我们要保证我们的测试稳定,首先这些要把它隔离掉。

Q5:测试驱动开发的实践只是单元测试,ATDD或BDD如何进行实践?

A: 我认为如果在TDD里自动化测试,其实是一个副产品,它是我们做设计或者Task产出的一个结果,另一方面就是测试,在整个过程中是用来验证我们所做的东西是否是正确。

我的风格比较偏实践,所以我不太会去区分它们到底是ATDD或者是BDD,是单元测试还是集成测试,我会刻意地去弱化它们之间的边界。因为我的目的很明确,就是要验证我写的东西的正确性,并且在第一时间能够发现问题。

我通常的做法是:先做一个集成测试拉通。当然我所说的集成测试是一个比较偏端对端的。假设我们是Java程序员,对于后端来说,我们先唤起整个Spring容器,从接口发请求,最后得到的回应是什么,这就是一个比较高层集成测试,把基本的Happy Path拉通,后续再补充各种内部的分支,全部用Unit Test来做。所以我不会去纠结它到底是ATDD还是BDD,是一个单元测试还是集成测试。总结来说就是:我究竟要测什么,那我就去写什么。

Q6:TDD模式下,如何进行团队考核,有哪些相关的指标可分享一下?

A: 团队考核这个点我们团队并没有明确的指标。

我们团队的伙伴都很积极向上,我们都想把优秀的实践变现,真正地服务于我们的客户。所以,我们团队的考核方式,通常是内部或者整个公司层面互评,以及同行互评,以此来看大家对我们的成果是否认可。

Q7:对于同一开发人员而言,TDD是如何能帮助他做简单设计的,能否举个例子?

A: 如何做简单设计是TDD比较常见的一个场景。

TDD有一个重要前提就是:我们先做任务分解,然后再做TDD。那么TDD是如何帮助做设计的?

第一点:先写测试。假设我们Task、任务分解都已做好,测试用例和验收标准也已经分解出来了。这时候是可以写出自动化测试的。但如果我们的自动化测试写不出来,就要好好反思一下,设计是不是有问题或者没有做到位?因此,先写测试就会在一开始将问题暴露出来。如果我们后写测试会发生什么呢?我先尝试着写大量的产品代码,但是还没有去验证它。等产品代码写完后,验证它的时候发现不对。通过这种更早的介入并验证设计的正确性,能够改善我们的设计。

第二点:当我们发现一些代码的实现或细节不尽人意时,如果这些代码有完善的自动化测试套件来保障,我就更有信心和勇气去修改它们,这样就对我们产生了一种正向的心理作用,让我更积极地去改善我的代码质量。这也是一个潜移默化改进设计质量的方法。

Q8:TDD开发是有步骤的,需求最开始是从哪里来的?

A: 当我们接到一个项目时,会有一个前期启动阶段,这个时间一般在3天到两个星期,一般不会超过两个星期。

启动阶段我们首先要把项目或者产品的愿景梳理清楚,了解它的用户人群有哪些。再与高层进行进一步的沟通,获得一些产品上的想法,最终得到一个大致的产品方案。

得到产品方案后,我们一般会通过用户旅程再结合一些其他的工具,把Epic找出来,将它分解成Story,团队会对Story做详尽的评估,最终得到一个Story List。其中包括它的优先级和Story点数。做好了这些后,团队就会对要做的产品或项目有一个统一的基础认知。

当然,在项目管理层面,也有很多内容需要跟进,比如Release Plan以及近两个Iteration Plan。

这些都是我们前期要做的准备工作,但是到这里还不能开始做TDD,因为还要再进行多次需求对齐,并通过IPM进一步做需求对齐。迭代规划过后,开发会拿到这张Story List并对其进行澄清,也就是开卡。只有开卡完成并且做了tasking过后,就开始做TTD了。 

Q9:用户只要求解决问题不愿更多地探讨需求,如何去挖掘背后的需求,当用户给出的解决方案和我们挖掘的需求不同时怎么做?

A: 这是我们做交付过程中遇到的比较常见的问题。通常交付团队对整个方案的了解是更加清晰的,有时候我们认为客户给我们讲的他们的是需求,但实际上是他需要的解决方案。

这时候我们就要及时跟他们沟通,通过他的解决方案,找到背后的真实需求,在大多数时候这个方法是奏效的。

但有时会遇到比较坚持的客户。尤其是一些传统甲方,这种情况会比较常见。我们在做交付的时候,还是需要尽可能去引导客户。但如果客户非常坚持,我们就需要做好双方的责任划分。

Q10:在项目前期,都需要什么样的角色的人员参与进去呢?

A: 我们团队的角色都比较简单化,启动阶段一般是BA加核心开发或Tech Lead。如果是有QA的团队,QA也会参与,基本上是这几种角色。开发人员会在启动阶段稍微靠后的时间点介入,因为这时我们会对所有的Story进行估算,虽然我们最终得到了估算数字,但其实它更有价值的地方是所有人对要做的事情达到一个共同的认知。

Q11:在这个过程中,其实我们也会有经常会给客户做演示吗?他们也会经常参与进来吗?他们是怎么参与的?

A: 我们做TDD的目就是为了做敏捷。做敏捷的话,我们能够定期或者迭代式交付给用户他想要的东西,所以我们通过迭代交付我们所认为的客户期望的价值。每个迭代的最后一天,我们会给客户做show case,也就是说客户会经常参与我们开发的过程。所以客户的很多反馈就会在show case过程中给到我们,我们就可以安排在下个迭代。

Q12:如何把握好测试用例的优先级,是从简单到复杂还是其他形式?

A: 如果是不同Story下的测试优先级,那么首先是要处理Story优先级。

而同一个Story下的优先级比较常用的套路是走Happy Path,也就是正常路径;正常路径走通后,再走Alternative Path,就是可选路径,比如有些分支,但是它也是一个业务上真正有用的一个分支;最后再走Sad Path,即异常路径。根据这个大原则,排出来的测试优先级就大差不差了,可以再根据具体情况进行细节调整。

Q13:以TDD的方式进行开发,对测试部的工作有多大影响?公司的人员分配如何调整呢?

A: 如果是一个使用TDD的团队,那这往往是一个敏捷团队,一般的状态就是全功能团队。全功能团队是按照产品或项目组织的,会覆盖包含测试人员在内所有角色,以这样的组织方式运作才会发挥最大价值。

现实是很多开发团队也想做TDD,但我认为如果无法改变组织架构,开发人员自己做TDD也没有太大问题。做TDD是要给测试人员来输入的,测试人员还是要写测试用例。

在写验收标准或者写测试用例的时候,测试人员都应该更多地去参与,把测试工作前置,在开始就参与到开发的过程中。后续,自动化测试会承接大量测试工作,很多手动的、机械的重复性工作就可以省掉。这对测试人员是一个很好的影响,让他们可以做更多思考的、创造性的工作。

以测试的视角帮助产品、开发做一些前期工作,把需求等各方面想得更加全面。甚至可以假设一下,让测试人员来写验收标准。这样传统测试人员所做的工作都已经集成到代码中,在代码上体现了,最后真正需要手动做的是一些探索性测试,大部分时间是在赋能。这是一种很新颖很理想化的状态,也是我们所有人努力的方向。

Q14:开发写的测试怎么检查?

A: 这个问题其实承接前一个问题,测试与开发已经在一起工作,就不需要额外做什么了。

当然,这个可能是在问到底测试什么?测试代码怎么保障?这可能也是很多做TDD伙伴的一个疑问。所有的代码都不能脱离业务,都是服务于业务的。测试代码一定是检查业务逻辑而非实现逻辑,这就应与验收标准挂钩,也就是来自Story的验收标准。如果测试不够全面,那也是大家对Story的验收标准讨论不够全面,其实就变成了整个团队的问题了。

Q15:怎么样的验收标准就算完整或者可以了?

A: 如何写好验收标准或User Story是很需要去考究的一件事情,这其实这跟测试是一回事。去做交付,不管测试还是写User Story,验收标准里面的每一条标准跟测试用例,都应该是对应的。

如何写好验收标准也是有很多方法的,可以在网上找到很多相关说明,无法在此处一一列明。具体到比如刚才说如何写测试的方法,可以按Happy Path、 Alternative Path、Sad Path的方式走下来,尽量在每一个点都把它当前层次的问题穷举掉。

Q16:开发的时候大中小测试是怎么进行的?是先写大测试还是先写小测试?比如端到端的大测试,不同层级的我们先写哪个?

A: 这也是比较常见的一个问题。我们团队的习惯是先写这种比较大的测试,大测试更能够表达业务的完整性,但是它的通过应该是比较困难,没有办法很短的时间就让测试通过。

我们团队的做法,是先写一个认为是端到端,但不包含UI的测试。这个测试首先走一个Happy Path,让这个过程走通。再根据我们的剩下的验收标准,补充剩下一些分支或一些中断的情况。这些基本上都是以Unit Test的方式来呈现的。

Q17:老板不懂技术和IT管理,如何向老板证明TDD带来的质量提升收益超过实践TDD所增加的时间成本?

A: 短期内很难证明。如果把时间线拉长,看最终团队的交付指标、客户的满意度,是能够看出成果来的。看最终一年省了多少成本,创造了多少收益,说服起来是比较容易的。但有一种情况是不让用TDD,那就没办法证明;没办法证明,就更不让用TDD,变成了死循环。所以能够证明TDD收益高于成本的前提是领导能够接受一部分人先TDD。


Q18:写测试用例的成本跟开发成本比例大概是怎样的?

A: 测试代码的比例和产品代码的比例并没有一个确切的数值,首先认为它不是累赘就好。我们团队没做过完整统计,大概就是在1.3-2之间。写测试用例用TDD的方式的代码量是不用TDD方式代码量的1.2到2倍这样。

还有一个角度是不光要看代码量,如果不用TDD,写代码后还要花时间测试、找Bug;而用TDD,先写测试代码,就可能是秒级。这就是TDD的好处,可以得到非常密集的单元测试套件,可以快速定位问题。

Q19:为了保证测试脚本一直可用,需要定期或每一天把测试脚本全量跑一遍吗?

A: 在我们的团队实践中,要求4次commit就跑一次全量,也就是说三四个单元测试跑完需要集成到主干时就跑一次全量,每次集成的时候都要跑一次全量。而多长时间集成一次呢,其实是越快越好,时间越短越好。这样的话,我们一般是10分钟-1小时之间就会跑一次全量。总之,就是单个脚本需要每时每刻在跑,全量最少需要每天都跑一遍。

Q20:有没有遇到过开发没有想清楚,就一边设计一边开发的情况?

A: 有遇到过这种问题,一般在开卡之前,团队需要确定好相关细节。如果出现了这种情况,我们需要在回顾会中将问题抛出来和大家一起讨论、一起解决。

Q21:有愿景,但需求一直在变,应如何确定合同金额?

A: 这个问题其实是一个敏捷合同的问题。我举一个例子,敏捷合同能够使甲方跟乙方的关系,像一个公司中的开发团队与业务团队的关系一样。这种关系是如何打造的呢?如果甲方跟乙方签的是个闭口合同,甲方的诉求肯定做得越多越好,乙方的诉求肯定是做得越少,所以他们天生是对立的。而敏捷合同能够将双方之间的利益冲突抹掉,变成一个雇佣关系。敏捷合同更多其实是一个团队跟一家公司这样的一个合作模式:整个专业化的团队受雇于一家雇主,按照市场或其他标准为团队付月薪或年薪。

实际上,敏捷合同是按迭代或按月来进行结算的,所以我们需要提高客户满意度,否则客户就有权取消我们合作。就像是雇佣单独的个体和雇佣高度专业化的团队来说,肯定是雇佣高度专业化的团队更加合适。那这个前提就是双方要建立一个比较好的信任关系。

信任关系的建立也是比较难的。对于了解敏捷的客户来说,会更容易认可这种方式,我们可以通过圈内朋友介绍等方式来筛选一些双方都认可的合作伙伴;而对于传统客户,我们需要通过长时间的合作,彰显我们的水平、认知以及态度来建立这个信任关系,签署敏捷合同。

此外,RRPL里也有敏捷合同的实践,大家可以关注一下。

Q22:开发人员会交叉写单测吗?如何保证开发人员的单测质量?

A: 我们可以尝试一下极限编程中的结对编程。结对编程其实是代码评审的一个变种。如果想保证开发人员的单测质量,那我们就需要做好代码评审。以我们团队的实际流程来说,开卡时有个开卡流程,开完卡再做任务分解、写单测等。过后我们会有一个叫shoulder check的过程来保证质量。

Q23:TDD能给业务或决策者带来哪些收益,可以驱动决策者推行TDD模式?尤其是多交付团队(交付多产品)的场景。

A: TDD 能给业务或决策者带来的收益,刚才在前面简单说了下,就是能提升IT团队的敏捷性。提升IT团队敏捷性,也是进一步提升业务团队的敏捷性。往大来讲,可以提升团队对市场的响应度,也是引入敏捷或者敏捷转型的一个好处。这些其实都是相关联的。因为TDD是敏捷的核心实践,而敏捷又能够帮助企业提升市场响应能力,所以我觉得天生他们之间是有着天生的关联的。

Q24:TDD有如此多好处,那在实践TDD的过程中有没有什么坑?

A: 做TDD确实是有一些坑,因为我自己一路走过来,也是踩过一些坑的。首先我个人以前比较常犯的一个错误,以及我见过的一些伙伴们常犯的一个错误——过分关注测试,也就是T,而不是关注于D。我们刚才讲到TDD是一个软件开发方法,而非一个测试方法。但其实很多人会过分地强调测试,这样就容易走偏。不应为了TDD而TDD。

刚才提到的过分关注测试,一个是测试覆盖率,另一个是如何去写测试本身。测试可能会陷入一些细节,比如陷入一些技术细节,它不是关注业务。此外,过分关注于T,其实也是将TDD认为是一个测试工具,而不是开发工具。举个例子,如果认为TDD是个测试工具,做测试时虽然后补测试也可以,但往往后补测试跟前面先写测试,这两者是完全不一样的。刚才也讲到了后写测试,它会让你失去通过测试来驱动架构并使其变得更好的一种动力。

另一个坑是过分专注细枝末节。在圈子里面有一种争论:到底是写单元测试还是写集成测试?到底什么叫单元?是一个类还是一个方法?不论是哪种,这些我认为都是在关注技术实现,而不是关注业务本身。这样的测试其实是极其不稳定的。只要我们的方案有一点变化或模型产生变化,这个测试它就变得不再有效。这样实践下来,我们不仅不会觉得TDD给我们带来任何好处,反而觉得TDD是一种累赘,给我们增加了非常多的负担。所以我们还是要根据User Story里的验收标准来。这些都需要一些刻意的训练。此外,做 TDD 之前一定要做任务分解,不管任务分解是在大脑中完成还是通过白板或者纸上完成的,这个步骤一定要做。因为任何一件伟大的事情,都需要我们分解成小的问题,这样才能处理掉。

Q25:TDD之后的代码评审如何做?代码评审关注业务还是代码规范以及代码结构,亦或是两方面都关注?

A: 我觉得应该两方面都要关注。因为一个软件系统,首先其代码是服务于业务的,这肯定没有错。所以如果用代码去表达业务逻辑,它的表达是否到位,肯定是要Review的。代码的结构以及规范、设计也是很有必要的,因为我们保持一个良好的设计,能够让我们在后续的过程当中走得更快,否则我们背负了太多的技术债务,其实越后到后面就越走越慢。


    发表评论
    通过审核后显示您的意见