TDD 的原理和使用场景

简介: 文章里主要讲了 3 种使用 TDD 的场景:修 Bug 时,写纯函数时,以及设计 UI 时。我感觉在写纯函数(数据转换),以及写接口时(Node 端开发)时用的比较多,修 Bug 嘛,实际情况都是业务 Bug,要用测试复现是比较麻烦的。设计 UI 前写测试也是比较麻烦的。总之,大家应该都会有自己使用 TDD 的场景,找到适合自己的就好。需要注意的是,千万别提前做优化,特别是你还不确定你的项目要发展到什么程度时。

image.png

前言



哈喽,大家好,我是海怪。


说起前端测试,有一个东西肯定是逃不掉的,那就是 TDD —— 测试驱动开发。很多前端大佬也都非常喜欢用 TDD 的模式来编程。因为它不仅可以通过测试保障代码质量,还能创造一个良好的开发环境来提高开发效率。


然而,有些同学会对此嗤之以鼻,觉得先写测试再写业务不是浪费了那 50% 的工时么?根本没时间写业务代码呀。我觉得这部分同学其实并没有搞清楚 TDD 的适用场景以及它要解决的问题。正好 Kent C. Dodds 在他这篇 《When I follow TDD》 里聊了关于 TDD 的一些想法和思路,今天就把这篇文章分享给大家~


正片开始



测试驱动开发(TDD)包含了 3 个步骤,一般也被称为 “红,绿,重构循环”。


image.png


下面是它的工作原理:


  • 🚨 红色部分:在你还没添加新功能前先写一个测试。然后你会得到一个失败的测试用例(会看到 “红色” 的报错信息)。


  • ✅ 绿色部分:慢慢添加业务代码来让测试通过(看到 “绿色” 成功通过信息)。


  • 🌀 重构部分:再回过头看审视自己的代码,把它重构成高可读性和高维护性的代码(这一步最棒的地方在于之前写的测试用例会告诉你在重构时是否会破坏现有逻辑)。


  • 🔁 重复:这就是个循环,反正 😉 一直走下去,直到写完这个功能


在真实使用上,这个方法可能有所不同,有些人还会把 TDD 作为自己的开发信仰。而我会站在更实用的角度上使用 TDD,只在一些我觉得有好处的情况下使用它。


image.png


那么问题来了:“什么时候用 TDD 才是合理的呢?”。这其实很依赖你的开发直觉。坦率地说,这跟你用 TDD 的感觉和经验有很大关系。当然,也有一些我经常会用 TDD 的经典场景。


修 Bug 场景



当在修 Bug 时,我喜欢在修复之前先写一个测试来复现它。这么做可以给我带来非常大的信心,让我在通过测试后马上知道是什么原因导致的这个 Bug,这样一来,我就知道我实际上已经修复了这个错误,而不仅仅是围绕这个问题进行了测试。

在维护我比较关注的软件时,90% 的时间都遵循这种方法(并因此添加了测试)。特别是在我的开源项目中就这么做的。这是这类测试的一个例子。

要修 Bug 么?试试 TDD 吧。


纯函数场景



我不会测所有的工具纯函数(对大部分纯函数我会用集成测试来覆盖),不过,如果某个工具函数有足够的复杂度,而且必须要用隔离的单测来测,那这也是一个使用 TDD 的绝佳机会。一般这类函数,你代码里都会有定义比较清晰的输入和输出结构。

我想大多数人都经历过这样的情况(就算现在没有,以后会也有的)。以前我在 PayPal 的时候,我要在用户输入对应的金额准备转账时做格式转换。由于要考虑货币的精度,这个处理逻辑比你相像得要复杂得多(有的货币根本没有小数概念)。对货币金额做格式化就是一个做 TDD 很好的例子,因为输入和输出都是很容易想出来的。

另一个很好的例子就是 我的项目 rtl-css-js 的测试(这也是开源的)。

要准备写纯工具函数么?试试 TDD 吧。


定义良好的交互场景



直到我创建了 Testing Library 后,我才认为用户界面的 TDD 在 Web 上确实可行,因为:


当你在 测代码实现细节 时,做 TDD 是没有意义的。


老实说,如果你在测代码实现细节,做任何测试都是没有意义的(它们只会拖慢你的速度)。TDD 一部分的意义在于帮助你思考:如何从在不考虑细节情况下从外部构建你的应用,这样你就会在设计项目时盯住你的主要目标,而不会钻入牛角尖。当你知道要做什么而不是想知道要怎么做的时候,它会对你有所帮助。


在 Testing Library 出来前的一些流行工具(所有测试工具种类),它能够让你(鼓励你)去测实现细节。如果这时你要用 TDD,你就得知道(比如)你要创建一个叫 makeDonation 的私有方法,调用时,它会分别传入(而不是传反) amountcurrency 两个参数。这也导致人们总感觉做 TDD 纯属浪费时间,只是走走过场。

不过现在 Testing Library 可以让你关注于用户交互,而不是实现细节,你可以在设计和定义好用户交互后使用 TDD。


几年前我录的一个视频, 里面用 Login 组件展示了这样的方法。这已经是几年前的了,现在应该更容易实现。


要准备设计一个定义明确的 UI 么?试试 TDD 吧。


总结



到这里说差不多了。我敢肯定,其他人在做 TDD 实践时也有他们自己觉得合理的场景,这也挺好的。


如果我只是写点试验代码片段(我经常这么干)或者只是乱写写代码,那我肯定不会用 TDD 的。只有在项目在往正道发展时,我才会添加对应的测试。顺便说一下,我在使用类型检查工具时也是这么干的。这也是我一直遵循的 抽象思路


写测试,添加类型定义,对代码做抽象都是对你项目的投资。如果你不确定创建的东西是否会长期存在,那么进行这些投资是没有意义的。如果你不确定在你完成时你创造的东西最终会变成什么样,那么这些投资也可能是不明智的。还有就是这些错误的投资所造成的沉没成本最终也会沦为一些不优雅的解决方案,最终会影响你的一些判断。


相关文章
|
前端开发 JavaScript
常见的8个前端防御性编程方案
常见的8个前端防御性编程方案
172 0
|
4月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
5月前
|
存储
hyengine设计问题之通用性和定制性如何解决
hyengine设计问题之通用性和定制性如何解决
|
6月前
|
开发框架 前端开发 关系型数据库
Winform开发的快速、健壮、解耦的几点建议
Winform开发的快速、健壮、解耦的几点建议
|
8月前
|
安全 Java 开发者
Java编程:深入探索其原理、特性与实战代码
Java编程:深入探索其原理、特性与实战代码
63 1
|
8月前
简述几种常用数值方法的优势及适用性
这篇文章简要介绍了几种常见的数值计算方法在解决偏微分方程中的应用。偏微分方程被用来描述自然界的物理现象,而当它们难以直接求解时,数值方法如有限元法(FEM)、有限差分法(FDM)、有限体积法(FVM)和边界元法(BEM)成为常用工具。有限元法适用于复杂问题,但计算量大;有限差分法简单但对复杂几何形状处理困难;有限体积法对网格质量要求低,适合流体力学;边界元法则仅需处理边界,适合边界主导的问题。各种方法各有优劣,常结合实际问题组合使用。例如,云道智造的伏图仿真平台集成多种数值方法,支持多物理场耦合仿真。
433 0
|
设计模式 Java 数据库连接
解锁设计模式的神秘面纱:编写无懈可击的代码之原型设计模式
解锁设计模式的神秘面纱:编写无懈可击的代码之原型设计模式
53 1
|
缓存 Java 编译器
探究Java方法的优化与最佳实践:提升性能与代码可维护性
探究Java方法的优化与最佳实践:提升性能与代码可维护性
184 0
|
Arthas 缓存 算法
如何写出高性能代码(二)巧用数据特性
同一份逻辑,不同人的实现的代码性能会出现数量级的差异; 同一份代码,你可能微调几个字符或者某行代码的顺序,就会有数倍的性能提升;同一份代码,也可能在不同处理器上运行也会有几倍的性能差异;十倍程序员 不是只存在于传说中,可能在我们的周围也比比皆是。十倍体现在程序员的方法面面,而代码性能却是其中最直观的一面。
195 0
如何写出高性能代码(二)巧用数据特性
|
监控 测试技术 应用服务中间件
软件测试面试题:做性能测试时你用过哪种测试工具?请说明其工作原理或举例说明工作流程。
软件测试面试题:做性能测试时你用过哪种测试工具?请说明其工作原理或举例说明工作流程。
130 0