對於軟體工程師來說,「撰寫單元測試」已經是一個必須具備的技能,撰寫好的單元測試不僅能夠確保程式運行正確,也能夠降低後期重構、維護的成本,可以說是一舉多得!
而在單元測試越來越重要的情況下,就誕生了 「TDD(測試驅動開發)」 的開發流程,因此這篇文章我們就來介紹一下,TDD 到底是什麼、以及要如何使用 TDD 來開發程式吧!
TDD 的全稱是 Test-Driven Development,中文翻譯為「測試驅動開發」,而 TDD 的核心理念,就是 貫徹「先寫測試、再寫開發」的精神。
也因為 TDD 的核心理念「先寫測試、再寫開發」比較抽象,所以以下我們就直接透過一個例子,來比較一下「傳統的開發流程」和「使用 TDD 的開發流程」的差別在哪裡。
一般我們在開發程式時,比較常見的流程為:
所以在傳統的開發流程中,當我們拿到需求時,基本上就是先動手寫程式,先去實作該功能出來,而等到功能都實作的差不多之後,最後再補足單元測試,確保程式運行正確,這樣子就算完成這個功能的開發了。
舉例來說的話,假設我們現在要實作一個「計算機的加法功能」,那麼我們就可以先寫出下圖左的程式(以 Java 為例),去實作加法功能出來。
而當我們實作完左邊的加法功能時,就可以再去撰寫右邊的單元測試,使用單元測試去驗證我們所寫的程式是否正確,因此到最後,我們就實作完「主功能程式」和「單元測試」的程式了。
所以上述這樣子的做法,就是最常見的傳統開發流程,也就是照著「先寫開發、再寫測試」的步驟,去完成一個功能的開發。
而在了解了傳統的開發流程之後,接著我們就可以來介紹 TDD 的開發流程是什麼了!
當我們使用 TDD 時,首先第一步,就是 「只宣告功能的方法名稱,但卻不實作他的內部程式」。
所以舉例來說的話,假設我們想要實作「計算機的加法功能」,那我們第一步,就只能夠先去宣告這個 add()
方法,但是不能夠去實作這個功能內部的程式。
這一步對於習慣傳統開發流程的工程師來說,其實就是非常反人類的一步了😂,人生從來沒遇過只需要宣告方法名稱、但是不需要實作程式的要求!
但是沒關係,建議大家就先接受 TDD 就是這樣的流程,所以當我們使用 TDD 時,第一步就是只宣告方法名稱,但是不實作他的內部程式。
宣告完方法之後,接著也是很反人類的第二步來了。在第二步中,我們就要 「先根據這個方法的用途,憑空寫出他的單元測試出來」。
舉例來說的話,因為我們想要實作的是「計算機的加法功能」,所以邏輯上,這個功能應該要能夠正確執行加法的操作才可以。因此我們可以直接在右邊撰寫一個單元測試,並且在這個單元測試中,就去測試 add()
方法的行為是否正確。
所以在這個單元測試中,當我們去 call add(1, 2)
方法時,就「預期」他的返回結果應該要是 3 才對(因為抽象的邏輯意義上,add()
方法就是要去執行加法操作,所以 1+2 要等於 3 才對),程式如下圖右所示。
所以在 TDD 的第二步中,我們就會直接根據這個方法的抽象邏輯,直接去撰寫單元測試出來,去「預期」這個方法的行為為何。
不過當然啦,因為我們目前在 add()
方法中還沒有實作任何一行程式,所以當我們運行這一段單元測試的程式時,單元測試就會運行失敗,因此產生「紅燈」的結果(雖然此時單元測試運行失敗,但是這也是 TDD 的開發流程一環,因此這裡出現紅燈是正常現象)。
老實說步驟二是大家一開始在接觸 TDD 時,最容易碰壁的一步,因為通常我們在實作程式時,會一不小心就往下鑽研去思考實作細節,但是卻忽略了「這個方法本身的用途」為何。
因此在使用 TDD 開發程式時,我們就得換個角度來思考,在真正實作程式的細節之前,反而是要先從大方向去規劃每一個方法的用途為何,這樣子後續在實作程式時,才能夠寫出功能拆分完整、職責分明的程式了!
在我們經歷了第二步最難熬的一關之後,後續的步驟就比較容易了!
因為在第二步中,我們已經寫好測試 add()
方法的單元測試了,所以在第三步中,我們就可以回頭去實作 add()
方法中的邏輯,將這個功能真正的實作出來。
而在我們實作完 add()
方法中的程式之後,這時候我們再回頭去運行單元測試,理論上就要能夠運行成功了!因此當我們運行單元測試時,單元測試就會顯示「綠燈」,表示單元測試成功通過。
所以透過 TDD 的開發流程,我們最終也是可以實作完「主功能程式」和「單元測試」的程式了!
所以透過這兩個流程也可以發現,不論我們使用的是「傳統的開發流程」、還是「TDD 的開發流程」,我們最終所實作完的程式,其實是一模一樣的,就是會包含「主功能程式」和「單元測試」這兩部分,因此不論我們使用哪一種方式來開發,最終的產出都是一樣的。
只不過 TDD 相對於傳統的開發流程而言,就是提供了另外一種開發思路給我們,讓我們在真正實作程式的細節之前,能夠先從大方向去規劃每一個方法的用途為何,進而寫出功能拆分完整、職責分明的程式了!
所以總結上述的介紹的話,現在我們回頭來看 TDD 的定義,就可以更了解 TDD 的核心理念是什麼了。
TDD 的全稱是 Test-Driven Development,中文翻譯為「測試驅動開發」,也因為 TDD 是透過「撰寫單元測試」去驅動「程式的開發」,所以 TDD 的核心理念,就是貫徹「先寫測試、再寫開發」的精神。
而 TDD 的開發流程,也可以總結成下面這張圖:
所以大家如果有興趣想嘗試 TDD(測試驅動開發)的話,就只要照著上述的步驟實作,就可以體驗 TDD 的開發流程了!
以下僅是主觀個人看法,不代表所有人的想法唷!
我之前在工作中有使用 TDD 來開發過,老實說,我覺得 TDD 沒有很好用😂,個人感覺還是一般的傳統開發流程(先寫好主程式,再寫單元測試)比較有效率。
之所以覺得 TDD 不好用的原因,是因為我還是滿常會卡在步驟二,也就是會卡在「主功能還沒實作出來,憑空去寫單元測試」的這個步驟。
如果是比較小型的專案,因為對每一行程式都比較熟,所以我對於憑空寫出單元測試還算能夠適應;但是如果是那種比較大型的專案,牽涉到跨國團隊的合作的話,就有點難對 project 的每個環節都很熟悉,所以這時候就比較難去「預期」某個功能的返回結果是什麼這樣。
所以以我之前的工作經驗來說,我覺得 TDD 用起來沒有想像中的順手,但也有可能是我抓不到訣竅就是了🥹。
不過!如果大家沒有使用過 TDD 來開發過的話,我仍舊是非常推薦可以使用 TDD 來開發看看的!畢竟 TDD 真的是一個很神奇的開發方式,在認識 TDD 之前,我從來沒有試過這種「反著寫」的方式來寫程式🤣,所以一開始接觸的時候還是覺得滿有趣的。
如果大家對 TDD 有興趣的話,也可以再上網搜尋 TDD 的相關介紹,看看其他大神是如何使用 TDD 來開發的,或是如果你本身是 TDD 大師的話,也歡迎回信和我分享你的 TDD 秘訣🙏。
TDD 真的是神奇的開發方式!推薦大家有機會都可以去體驗一下~
這篇文章我們有去介紹了 TDD(Test-Driven Development,測試驅動開發)的核心理念是什麼,並且也介紹了 TDD 的開發流程,了解要如何透過「撰寫單元測試」去驅動「程式的開發」。
如果你對後端技術有興趣的話,也歡迎免費訂閱 《古古的後端筆記》電子報 ,每週二為你送上一篇後端技術分享,那我們就下一篇文章見啦!