TDD测试驱动开发︱一个完整的TDD测试驱动开发演练案例
2022-11-06
来源:逸言 我是张逸
合要求,就不允许创建该Answer,而是抛出异常。所以,这里的部分验证逻辑是在创建Answer之前就应该存在,当然就不应该由Answer承担了。
针对第三个任务,验证结果的逻辑不应该由boolean型或错误码来表现。对于表达一种错误规则来说,如果你将其看做是一种业务规则,最好的表达方式是采用自定义异常,除非这门语言允许返回两个值(例如Go语言支持返回多个字,但并不支持异常)。对此,在第二个任务中已有描述,这里不再赘述。
重构:Answer的验证逻辑
在开发第二个任务时,我们已经在Answer类中定义了validate()方法。现在,InputValidator类又提供了validate()方法,且其中部分逻辑是相同的。在实现时,应该如何重构现有代码?
第四个任务
还剩下两个任务:
记录并显示历史猜测数据
判断游戏结果
究竟应该选择哪一个任务作为第四个任务,并没有定论。从业务逻辑看,“判断游戏结果”任务更重要,它才是整个游戏的核心逻辑。可从技术实现看,“判断游戏结果”可以依赖“记录并显示历史猜测数据”。因为分析“判断游戏结果”任务,实际上做了两件事:其一是判断猜测次数是否超过指定的6次;其二是判断每次猜测的结果。第二件事已经被我们开发的第二个任务覆盖。而对于测试次数而言,如果我们记录了历史猜测数据,那么这个次数也可以唾手可得。
讨论:测试驱动开发需要事先设计吗?
Martin Fowler的文章Is Design Dead?其实就是对此问题的正本清源。由于测试驱动开发提倡“测试先行,简单设计”,许多人就误认为TDD不需要设计,以讹传讹之下,甚至导致许多优秀的设计者抛弃了设计去实践TDD,最后得出TDD不可行的结论。
我个人认为,视场景而定,测试驱动开发仍可进行事先设计。设计并不仅包含技术层面的设计如对OO思想乃至设计模式的运用,它本身还包括对需求的分析与建模。若不分析需求就开始编写测试,就好像没有搞清楚要去的地方,就开始快步前行,最后发现南辕北辙。测试驱动开发提倡的任务分解,实际上就是一种需求的分析。而如何寻找职责,以及识别职责的承担者则可以视为建模设计。测试驱动更像是一种培养设计专注力的手段,就像冥想者通过盘腿静坐的手段来体悟天地一样,测试驱动可以强迫你站在测试的角度(就是使用者的角度)去思考接口,如此才能设计出表现意图的接口。但编写测试自身并不能取代设计,正如盘腿静坐并不等于就是冥想。
在开始测试驱动开发之前,做适度的事先设计,还有利于我们仔细思考技术实现的解决方案。它与测试驱动接口的设计并不相悖。解决方案或许属于实现层面,若过早思考实现,会干扰我们对接口的判断;但完全不理会实现,又可能导致设计方向的走偏。举例来说,如果我们要实现XML消息到Java对象的转换。一种解决方案是通过jaxb将消息转换为Java对象,然后再定义转换映射的Transformer,通过硬编码或者反射的方式将其转换为相关的领域对象。然后在执行了业务操作后,再将返回的结果转换为另一个Jaxb对象。而另一种解决方案则是通过引入模板,例如StringTemplate或者Velocity,定义转换的模板,然后进行替换实现。这两种解决方案的区别,直接影响了我们划分任务的方式。
我们选择“记录并显示历史猜测数据”作为第四个任务。同样,对于此任务,我们要事先考虑清楚,究竟应该由谁来承担
免责声明:
1、IT项目管理界发布的所有资讯与文章是出于为业界传递更多信息之目的,并不意味着赞同其观点或证实其描述。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请浏览者仅作参考,并请自行核实相关内容。
2、本站部分内容转载于其他网站和媒体,版权归原作者或原发布媒体所有。如文章涉及版权等问题,请联系本站,我们将在两个工作日内进行删除或修改处理。敬请谅解!