一篇了解TDD 的原理和使用場(chǎng)景
前言
哈嘍,大家好,我是海怪。
說(shuō)起前端測(cè)試,有一個(gè)東西肯定是逃不掉的,那就是 TDD —— 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)。很多前端大佬也都非常喜歡用 TDD 的模式來(lái)編程。因?yàn)樗粌H可以通過(guò)測(cè)試保障代碼質(zhì)量,還能創(chuàng)造一個(gè)良好的開(kāi)發(fā)環(huán)境來(lái)提高開(kāi)發(fā)效率。
然而,有些同學(xué)會(huì)對(duì)此嗤之以鼻,覺(jué)得先寫(xiě)測(cè)試再寫(xiě)業(yè)務(wù)不是浪費(fèi)了那 50% 的工時(shí)么?根本沒(méi)時(shí)間寫(xiě)業(yè)務(wù)代碼呀。我覺(jué)得這部分同學(xué)其實(shí)并沒(méi)有搞清楚 TDD 的適用場(chǎng)景以及它要解決的問(wèn)題。正好 Kent C. Dodds[1] 在他這篇 《When I follow TDD》[2] 里聊了關(guān)于 TDD 的一些想法和思路,今天就把這篇文章分享給大家~
翻譯中會(huì)盡量用更地道的語(yǔ)言,這也意味著會(huì)給原文加一層 Buf,想看原文的可點(diǎn)擊 這里[3]。
正片開(kāi)始
測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(TDD)包含了 3 個(gè)步驟,一般也被稱(chēng)為 “紅,綠,重構(gòu)循環(huán)”。
下面是它的工作原理:
- ?? 紅色部分:在你還沒(méi)添加新功能前先寫(xiě)一個(gè)測(cè)試。然后你會(huì)得到一個(gè)失敗的測(cè)試用例(會(huì)看到 “紅色” 的報(bào)錯(cuò)信息)。
- ? 綠色部分:慢慢添加業(yè)務(wù)代碼來(lái)讓測(cè)試通過(guò)(看到 “綠色” 成功信息)。
- ?? 重構(gòu)部分:再回過(guò)頭看審視自己的代碼,把它重構(gòu)成高可讀性和高維護(hù)性的代碼(這一步最棒的地方在于之前寫(xiě)的測(cè)試用例會(huì)告訴你在重構(gòu)時(shí)是否會(huì)破壞現(xiàn)有邏輯)。
- ?? 重復(fù):這就是個(gè)循環(huán),反正 ?? 一直走下去,直到寫(xiě)完這個(gè)功能。
在真實(shí)使用上,這個(gè)方法可能有所不同,有些人還會(huì)把 TDD 作為自己的開(kāi)發(fā)信仰。而我會(huì)站在更實(shí)用的角度上使用 TDD,只在一些我覺(jué)得有好處的情況下使用它。
那么問(wèn)題來(lái)了:“什么時(shí)候用 TDD 才是合理的呢?”。這其實(shí)很依賴(lài)你的開(kāi)發(fā)直覺(jué)。坦率地說(shuō),這跟你用 TDD 的感覺(jué)和經(jīng)驗(yàn)有很大關(guān)系。當(dāng)然,也有一些我經(jīng)常會(huì)用 TDD 的經(jīng)典場(chǎng)景。
修 Bug 場(chǎng)景
當(dāng)在修 Bug 時(shí),我喜歡在修復(fù)之前先寫(xiě)一個(gè)測(cè)試來(lái)復(fù)現(xiàn)它。這么做可以給我?guī)?lái)非常大的信心,讓我在通過(guò)測(cè)試后馬上知道是什么原因?qū)е碌倪@個(gè) Bug,這樣一來(lái),我就知道我實(shí)際上已經(jīng)修復(fù)了這個(gè)錯(cuò)誤,而不僅僅是圍繞這個(gè)問(wèn)題進(jìn)行了測(cè)試。
在維護(hù)我比較關(guān)注的軟件時(shí),90% 的時(shí)間都遵循這種方法(并因此添加了測(cè)試)。特別是在我的開(kāi)源項(xiàng)目中就這么做的。這是這類(lèi)測(cè)試的一個(gè)例子。
要修 Bug 么?試試 TDD 吧。
純函數(shù)場(chǎng)景
我不會(huì)測(cè)所有的工具純函數(shù)(對(duì)大部分純函數(shù)我會(huì)用集成測(cè)試來(lái)覆蓋),不過(guò),如果某個(gè)工具函數(shù)有足夠的復(fù)雜度,而且必須要用隔離的單測(cè)來(lái)測(cè),那這也是一個(gè)使用 TDD 的絕佳機(jī)會(huì)。一般這類(lèi)函數(shù),你代碼里都會(huì)有定義比較清晰的輸入和輸出結(jié)構(gòu)。
我想大多數(shù)人都經(jīng)歷過(guò)這樣的情況(就算現(xiàn)在沒(méi)有,以后會(huì)也有的)。以前我在 PayPal 的時(shí)候,我要在用戶(hù)輸入對(duì)應(yīng)的金額準(zhǔn)備轉(zhuǎn)賬時(shí)做格式轉(zhuǎn)換。由于要考慮貨幣的精度,這個(gè)處理邏輯比你相像得要復(fù)雜得多(有的貨幣根本沒(méi)有小數(shù)概念)。對(duì)貨幣金額做格式化就是一個(gè)做 TDD 很好的例子,因?yàn)檩斎牒洼敵龆际呛苋菀紫氤鰜?lái)的。
另一個(gè)很好的例子就是 我的項(xiàng)目 rtl-css-js 的測(cè)試(這也是開(kāi)源的)。
要準(zhǔn)備寫(xiě)純工具函數(shù)么?試試 TDD 吧。
定義良好的交互場(chǎng)景
直到我創(chuàng)建了 Testing Library[4] 后,我才認(rèn)為用戶(hù)界面的 TDD 在 Web 上確實(shí)可行,因?yàn)椋?/p>
當(dāng)你在 測(cè)代碼實(shí)現(xiàn)細(xì)節(jié) 時(shí),做 TDD 是沒(méi)有意義的。
老實(shí)說(shuō),如果你在測(cè)代碼實(shí)現(xiàn)細(xì)節(jié),做任何測(cè)試都是沒(méi)有意義的(它們只會(huì)拖慢你的速度)。TDD 一部分的意義在于幫助你思考:如何從在不考慮細(xì)節(jié)情況下從外部構(gòu)建你的應(yīng)用,這樣你就會(huì)在設(shè)計(jì)項(xiàng)目時(shí)盯住你的主要目標(biāo),而不會(huì)鉆入牛角尖。當(dāng)你知道要做什么而不是想知道要怎么做的時(shí)候,它會(huì)對(duì)你有所幫助。
在 Testing Library 出來(lái)前的一些流行工具(所有測(cè)試工具種類(lèi)),它能夠讓你(鼓勵(lì)你)去測(cè)實(shí)現(xiàn)細(xì)節(jié)。如果這時(shí)你要用 TDD,你就得知道(比如)你要?jiǎng)?chuàng)建一個(gè)叫 makeDonation 的私有方法,調(diào)用時(shí),它會(huì)分別傳入(而不是傳反) amount 和 currency 兩個(gè)參數(shù)。這也導(dǎo)致人們總感覺(jué)做 TDD 純屬浪費(fèi)時(shí)間,只是走走過(guò)場(chǎng)。
不過(guò)現(xiàn)在 Testing Library 可以讓你關(guān)注于用戶(hù)交互,而不是實(shí)現(xiàn)細(xì)節(jié),你可以在設(shè)計(jì)和定義好用戶(hù)交互后使用 TDD。
幾年前我錄的一個(gè)視頻, 里面用 Login 組件展示了這樣的方法。這已經(jīng)是幾年前的了,現(xiàn)在應(yīng)該更容易實(shí)現(xiàn)。
要準(zhǔn)備設(shè)計(jì)一個(gè)定義明確的 UI 么?試試 TDD 吧。
總結(jié)
到這里說(shuō)差不多了。我敢肯定,其他人在做 TDD 實(shí)踐時(shí)也有他們自己覺(jué)得合理的場(chǎng)景,這也挺好的。
如果我只是寫(xiě)點(diǎn)試驗(yàn)代碼片段(我經(jīng)常這么干)或者只是亂寫(xiě)寫(xiě)代碼,那我肯定不會(huì)用 TDD 的。只有在項(xiàng)目在往正道發(fā)展時(shí),我才會(huì)添加對(duì)應(yīng)的測(cè)試。順便說(shuō)一下,我在使用類(lèi)型檢查工具時(shí)也是這么干的。這也是我一直遵循的 抽象思路。
寫(xiě)測(cè)試,添加類(lèi)型定義,對(duì)代碼做抽象都是對(duì)你項(xiàng)目的投資。如果你不確定創(chuàng)建的東西是否會(huì)長(zhǎng)期存在,那么進(jìn)行這些投資是沒(méi)有意義的。如果你不確定在你完成時(shí)你創(chuàng)造的東西最終會(huì)變成什么樣,那么這些投資也可能是不明智的。還有就是這些錯(cuò)誤的投資所造成的沉沒(méi)成本最終也會(huì)淪為一些不優(yōu)雅的解決方案,最終會(huì)影響你的一些判斷。
好了,這篇外文就給大家?guī)У竭@里了。文章里主要講了 3 種使用 TDD 的場(chǎng)景:修 Bug 時(shí),寫(xiě)純函數(shù)時(shí),以及設(shè)計(jì) UI 時(shí)。我感覺(jué)在寫(xiě)純函數(shù)(數(shù)據(jù)轉(zhuǎn)換),以及寫(xiě)接口時(shí)(Node 端開(kāi)發(fā))時(shí)用的比較多,修 Bug 嘛,實(shí)際情況都是業(yè)務(wù) Bug,要用測(cè)試復(fù)現(xiàn)是比較麻煩的。設(shè)計(jì) UI 前寫(xiě)測(cè)試也是比較麻煩的??傊蠹覒?yīng)該都會(huì)有自己使用 TDD 的場(chǎng)景,找到適合自己的就好。需要注意的是,千萬(wàn)別提前做優(yōu)化,特別是你還不確定你的項(xiàng)目要發(fā)展到什么程度時(shí)。