
最初发布在 个人博客中 。
测试驱动开发似乎是一种简单的技术,但是它引起了各种各样的反应。 从人们认为这使您变得更加专业的人们到认为它已经死了的人们。
总体而言,我认为TDD发烧友的大力推动弊大于利。 当您对良好的编码习惯感到兴奋时,这很棒,但是当您开始强迫他人时,它可能会产生相反的反应。 它甚至有一个心理术语- 电抗理论 :
当某人承受巨大压力要接受某种观点或态度时,就会发生反抗。 反抗可能会使人采取或加强与原意相反的观点或态度,并增加抵抗力。
我认为这在某种程度上影响了开发人员更可能表达和分享为何TDD对他们不起作用的观点。 TDD是一种特定的技术,并且天真地认为它可以适用于所有人。 而且,没有人会因为不使用TDD而感到难过或不专业。 但是,TDD也许是适合您的技术,但是多种巧合使您得出结论,即它太难且不切实际。 在这里,我将分享一些想法,这些想法可能有助于您重新思考TDD体验。 其中有些是关于如何交替应用规则的想法,有些是关于如何改善测试体验的想法,即使您没有使用TDD。
你太严格地遵守规则
这来自所有教程和书籍,其中严格规定了规则。 TDD的第一定律指出:
除非要通过失败的单元测试,否则不允许编写任何生产代码。
从如此强烈的措辞看来,严格遵守规则似乎是必须的。 尽管所有这三个定律都准确地描述了TDD流程,并且一些开发人员确实严格遵循了它们,但应将其视为初步学习的材料。
学习规则,然后打破规则
对于TDD,这意味着一旦掌握了它的工作原理,就可以在感觉到它的工作时就应用它。 最初,严格的过程会教您如何编写可测试的代码。 但是稍后您可能会发现先构建结构并随后开始为逻辑编写TDD测试更加舒适。
您仅将其用于单元测试
TDD ==单元测试是一个常见的误解。 实际上,甚至名称是“测试驱动开发”,而不是“单元测试驱动开发”。 单元测试主要用在TDD示例和教程中,通常,TDD可以通过纯单元可测试功能很好地工作。 但实际上,该技术可用于任何类型的测试。
例如,我使用TDD编写了很多SQL查询。 有时我不确定我需要编写什么SQL,但是我只需要创建一个插入少量数据库行并期望得到一些结果的测试即可。 然后,我可以尝试不同的SQL查询,直到它起作用为止。 与API测试相同。 您可能需要修复JSON输出格式错误的错误。 您可以编写一个API测试用例,然后开始修复代码,而不是使用Postman进行手动测试。
您的测试基础架构太慢
TDD的最大好处是它实际上可以使您更快。 这是怎么回事。
编写新功能或修复现有流程可能会简化为两个步骤:
- 创建/更新代码
- 检查它是否按预期工作
TDD使您可以优化“检查其是否按预期工作”的速度。 您无需等待应用程序的重建,也无需打开浏览器,创建测试数据并查看代码是否按预期工作。 使用TDD,您可以立即看到结果。
但是,如果测试执行缓慢,那只会中断流程。 有人说测试应该在10秒或更短的时间内进行 。 我可以部分同意,因为当测试套件很快时,TDD对我来说感觉最好。 但是,我不同意运行一部分测试套件以提高速度(如果您拥有大型测试套件)是很不好的。 但是在使用该技术之前,还有其他方法可以提高速度。
首先,必须弄清为什么测试速度慢。 如果存在冗余数据初始化,或者每次都在重建数据库,则集成测试可能会减慢速度。 每个案例都是唯一的。 单元测试也是如此,具体取决于所使用的堆栈或工具。 找出它们的局限性和最佳做法,看看是否可以以任何方式提高速度。
如果没有其他方法可以提高速度(例如,IT测试自然比单元测试慢)。 您可以应用此技术,从而可以快速运行测试。 以特定的频率运行不同数量的测试:
- 当您进行少量代码更改时,最经常执行一次测试
- 一段时间后,或者如果您认为已进行了较大的更改,请针对特定功能/方法运行所有测试
- 在一段时间后,运行多个相关测试(可能是同一类/模块的所有测试)
- 最后,运行所有测试服
这不是一门精确的科学,您应该找到最有效的方法。 但是,不要过多考虑应该运行哪些测试。
您的测试基础架构不便
它与先前有关速度的陈述紧密相关。 为了提高TDD的效率,您必须使用舒适的工具(同样适用于在没有TDD的情况下编写测试的效率)。
作为示例,我可以提到两种非常重要的测试基础结构质量:
- 与单项测试相比,执行所有测试有多容易? 最好的情况是,您可以通过单击按钮或键盘快捷键来执行所需的测试。 进入控制台并输入正则表达式以匹配您要运行的测试是很乏味的。
- 断言错误有多清晰? 您无需解释测试失败的原因。 当您期望数组中的某些项目不好时,会出现诸如“ Expected true to false”之类的失败消息。
清单可以继续,但是主要目标是尽量减少对常规操作的思考。 相反,这使您可以更多地考虑您需要解决的实际问题。 如果测试基础架构阻碍了您的工作,并且使您过多地考虑如何开始编写或编写测试,那么在TDD上效率将非常困难。 这样,无论您在测试之后还是之前编写测试,都将变得烦人。
您仅将TDD应用于简单情况
为简单的逻辑编写测试,尤其是在涉及模拟的情况下,可能会感到有些尴尬。 您需要编写设置代码,初始化模拟对象,为方法调用添加断言等。最后,实际的代码只是“ if”语句和少量函数调用。 这可能会让人感到有些不知所措。
我并不是说您不应该在简单情况下使用TDD。 在学习的同时肯定会有所帮助。 但是仅申请简单的案例可能无法显示其全部潜力。 当我开始使用TDD时,似乎只能将其应用于新代码,并且仅应用于某些功能。 但是我已经开始在修复新的错误或向现有代码中添加新功能时使用它,它确实帮助我了解了如何在不同情况下应用它。
当您要执行复杂的逻辑时,TDD感觉最好。 您甚至都不知道如何实现它,但是它使您可以消除需求并最终获得可以正常使用的解决方案。 同时,它还增加了重构时的信心。
您正在测试太多实施细节
良好的测试清晰易懂。 使用TDD时,可以很容易地想到要预先编写什么测试。 但是,如果您试图过多地涵盖内部行为,则可能很难预先编写测试。
例如,当涉及到大量的存根和嘲笑时,就会发生很多事情。 这些测试很难编写,因为它们涉及断言,例如“该方法应使用这些参数调用3次”,等等。
我记得的另一个示例是使用Enzyme编写React测试。 有时我会进行一些测试,这些测试包括检查内部状态,检查组件如何渲染子组件等。当我开始使用React Testing Library时,使用TDD变得更加容易。 您无权访问内部细节,这迫使您考虑对组件进行不同的测试。 您无需关心正在渲染哪些子组件以及将哪些道具传递给它们。 相反,您可以编写期望呈现某些文本的测试,并且这样的测试绝对容易编写。