一篇了解TDD 的原理和使用場景
前言
哈嘍,大家好,我是海怪。
說起前端測試,有一個東西肯定是逃不掉的,那就是 TDD —— 測試驅動開發。很多前端大佬也都非常喜歡用 TDD 的模式來編程。因為它不僅可以通過測試保障代碼質量,還能創造一個良好的開發環境來提高開發效率。
然而,有些同學會對此嗤之以鼻,覺得先寫測試再寫業務不是浪費了那 50% 的工時么?根本沒時間寫業務代碼呀。我覺得這部分同學其實并沒有搞清楚 TDD 的適用場景以及它要解決的問題。正好 Kent C. Dodds[1] 在他這篇 《When I follow TDD》[2] 里聊了關于 TDD 的一些想法和思路,今天就把這篇文章分享給大家~
翻譯中會盡量用更地道的語言,這也意味著會給原文加一層 Buf,想看原文的可點擊 這里[3]。
正片開始
測試驅動開發(TDD)包含了 3 個步驟,一般也被稱為 “紅,綠,重構循環”。

下面是它的工作原理:
- ?? 紅色部分:在你還沒添加新功能前先寫一個測試。然后你會得到一個失敗的測試用例(會看到 “紅色” 的報錯信息)。
- ? 綠色部分:慢慢添加業務代碼來讓測試通過(看到 “綠色” 成功信息)。
- ?? 重構部分:再回過頭看審視自己的代碼,把它重構成高可讀性和高維護性的代碼(這一步最棒的地方在于之前寫的測試用例會告訴你在重構時是否會破壞現有邏輯)。
- ?? 重復:這就是個循環,反正 ?? 一直走下去,直到寫完這個功能。
在真實使用上,這個方法可能有所不同,有些人還會把 TDD 作為自己的開發信仰。而我會站在更實用的角度上使用 TDD,只在一些我覺得有好處的情況下使用它。

那么問題來了:“什么時候用 TDD 才是合理的呢?”。這其實很依賴你的開發直覺。坦率地說,這跟你用 TDD 的感覺和經驗有很大關系。當然,也有一些我經常會用 TDD 的經典場景。
修 Bug 場景
當在修 Bug 時,我喜歡在修復之前先寫一個測試來復現它。這么做可以給我帶來非常大的信心,讓我在通過測試后馬上知道是什么原因導致的這個 Bug,這樣一來,我就知道我實際上已經修復了這個錯誤,而不僅僅是圍繞這個問題進行了測試。
在維護我比較關注的軟件時,90% 的時間都遵循這種方法(并因此添加了測試)。特別是在我的開源項目中就這么做的。這是這類測試的一個例子。
要修 Bug 么?試試 TDD 吧。
純函數場景
我不會測所有的工具純函數(對大部分純函數我會用集成測試來覆蓋),不過,如果某個工具函數有足夠的復雜度,而且必須要用隔離的單測來測,那這也是一個使用 TDD 的絕佳機會。一般這類函數,你代碼里都會有定義比較清晰的輸入和輸出結構。
我想大多數人都經歷過這樣的情況(就算現在沒有,以后會也有的)。以前我在 PayPal 的時候,我要在用戶輸入對應的金額準備轉賬時做格式轉換。由于要考慮貨幣的精度,這個處理邏輯比你相像得要復雜得多(有的貨幣根本沒有小數概念)。對貨幣金額做格式化就是一個做 TDD 很好的例子,因為輸入和輸出都是很容易想出來的。
另一個很好的例子就是 我的項目 rtl-css-js 的測試(這也是開源的)。
要準備寫純工具函數么?試試 TDD 吧。
定義良好的交互場景
直到我創建了 Testing Library[4] 后,我才認為用戶界面的 TDD 在 Web 上確實可行,因為:
當你在 測代碼實現細節 時,做 TDD 是沒有意義的。
老實說,如果你在測代碼實現細節,做任何測試都是沒有意義的(它們只會拖慢你的速度)。TDD 一部分的意義在于幫助你思考:如何從在不考慮細節情況下從外部構建你的應用,這樣你就會在設計項目時盯住你的主要目標,而不會鉆入牛角尖。當你知道要做什么而不是想知道要怎么做的時候,它會對你有所幫助。
在 Testing Library 出來前的一些流行工具(所有測試工具種類),它能夠讓你(鼓勵你)去測實現細節。如果這時你要用 TDD,你就得知道(比如)你要創建一個叫 makeDonation 的私有方法,調用時,它會分別傳入(而不是傳反) amount 和 currency 兩個參數。這也導致人們總感覺做 TDD 純屬浪費時間,只是走走過場。
不過現在 Testing Library 可以讓你關注于用戶交互,而不是實現細節,你可以在設計和定義好用戶交互后使用 TDD。
幾年前我錄的一個視頻, 里面用 Login 組件展示了這樣的方法。這已經是幾年前的了,現在應該更容易實現。
要準備設計一個定義明確的 UI 么?試試 TDD 吧。
總結
到這里說差不多了。我敢肯定,其他人在做 TDD 實踐時也有他們自己覺得合理的場景,這也挺好的。
如果我只是寫點試驗代碼片段(我經常這么干)或者只是亂寫寫代碼,那我肯定不會用 TDD 的。只有在項目在往正道發展時,我才會添加對應的測試。順便說一下,我在使用類型檢查工具時也是這么干的。這也是我一直遵循的 抽象思路。
寫測試,添加類型定義,對代碼做抽象都是對你項目的投資。如果你不確定創建的東西是否會長期存在,那么進行這些投資是沒有意義的。如果你不確定在你完成時你創造的東西最終會變成什么樣,那么這些投資也可能是不明智的。還有就是這些錯誤的投資所造成的沉沒成本最終也會淪為一些不優雅的解決方案,最終會影響你的一些判斷。
好了,這篇外文就給大家帶到這里了。文章里主要講了 3 種使用 TDD 的場景:修 Bug 時,寫純函數時,以及設計 UI 時。我感覺在寫純函數(數據轉換),以及寫接口時(Node 端開發)時用的比較多,修 Bug 嘛,實際情況都是業務 Bug,要用測試復現是比較麻煩的。設計 UI 前寫測試也是比較麻煩的。總之,大家應該都會有自己使用 TDD 的場景,找到適合自己的就好。需要注意的是,千萬別提前做優化,特別是你還不確定你的項目要發展到什么程度時。
























