iT邦幫忙

3

【如何高效開發 ? 】測試驅動開發 | 3 大法則 + 5 大好處

  • 分享至 

  • xImage
  •  

撰寫單元測試,速度更快 !

Yes

大綱

  • 除錯的日常
  • 測試驅動開發
  • 三大法則
  • 五大好處
  • JUnit 示範
  • 違反直覺的力量

除錯的日常

工程師的日常,是不斷的與程式錯誤(Bug) 進行搏鬥

「謹慎」

是工程師的「美德」,也是工程師的痛苦來源 :

  • 「修正」 只花不到 10 分鐘
  • 「測試」 卻花 10 倍以上時間

如此情況,你可以...

撰寫「單元測試」- 使用程式來測試程式,只是要多花了一點時間。

你知道嗎?

如果正確使用「單元測試」的方法 :

甚至會比不寫測試的開發流程,開發的更加快速 !

測試驅動開發

傳統的單元測試流程

傳統開發上的單元測試流程,會先寫產品程式,在寫測試程式。

  • 好處: 都有測過 BUG 比較少
  • 壞處: 比較花時間,相對麻煩

大概率會被省略

如果產品程式已經完成了,在 UI 介面上都沒有測出問題來。

怠惰之心,人皆有之。

工程師,可能會直接略過這一段。

即便是團隊要求,當任務時程緊急的時候,還是會有很大的概率,會被省略。


書中的知識

  • Clean Code 無瑕的程式碼 - 敏捷軟體開發技巧守則
  • The Clean Coder 無瑕的程式碼 番外篇 - 專業程式設計師的生存之道

這兩本書籍,相同作者,但不同主題。

書中都提到 :

測試驅動開發 (Test Driven Development , TDD)

藉由先撰寫「測試」的程式碼 ,「驅動」產品程式的「開發」。


「先寫測試的程式設計方式」

因為有各種的優點,章節的結論就是直接認定 :

「 TDD 是專業人士的選擇 」

不使用 TDD 的程式設計師,只能代表:

可能還「 不夠專業 」
 

001.pro


三大法則

測試驅動開發,有三大法則 :

TDD

第一法則

在撰寫一個單元測試前,不可撰寫任何產品程式

要先從測試程式開始撰寫,絕對不要先撰寫產品程式。

「順序」非常重要

第二法則

只撰寫剛好無法通過的單元測試,不能編譯也算無法通過

撰寫的測試程式,結果必須是失敗的,而且是「剛好」失敗的。

「不要一次完成所有的測試程式」

第三法則

只撰寫剛好能通過當前測試失敗的產品程式

撰寫的產品程式,結果必須是成功的,而且是「剛好」成功的。

「先完成一個小目標」

循環動作

然後,依據這個法則,大約 每 30 秒就會執行一次程式碼:

  • 無法通過的單元測試: 會驅動你,完善產品程式
  • 通過的單元測試: 會告訴你,產品程式,沒有問題。可以繼續撰寫 下一個測試程式。

如此就會構成一個循環,不斷重複。測試的程式碼與產品的程式碼就會同步增長並且互相匹配。

相比於傳統開發上的單元測試流程,割裂的兩個動作就會合而為一 :

測試就是開發,開發就是測試。
  • 不會有所謂「麻煩」的問題
  • 更不會出現,時程緊急時,省略單元測試的問題

快速的原因

因為兩個動作,是在同一時間被撰寫出的,速度肯定是比分開兩步驟執行的更快 !

但為什麼會比不寫單元測試的開發流程,還要更快 ?

關鍵點在於 :

「極短的程式碼執行週期」

「trial and error」 (嘗試錯誤的方法),在極短的時間內,以極高的頻率,高速運作。

002.music

修正與反饋組合成的節奏,就像鋼琴樂譜一樣 ,優美且流暢的彈奏出來。


五大好處

依據 TDD 三大法則開發的程式,就會帶來五大好處 :

003.good

  • 確定性
  • 缺陷注入率
  • 勇氣
  • 文件
  • 設計

確定性

依據這個法則,就會撰寫非常多的測試程式,並且測試程式相比於產品程式,只會多不會少。

003-1.good

程式修改後,執行「單元測試」的綠燈,會非常的確定,程式與當初開發的預期結果

 是一致的

缺陷注入率

「缺陷注入率」指的是出現錯誤缺陷的比率,原因相似於「確定性」。

003-2.good

越低的錯誤率,維護程式的成本就會越小,也會是每個開發者追求的目標。


勇氣

「勇氣」指的是面對糟糕程式碼的「勇氣」

面對糟糕的程式碼,你會想要改它,但又怕會把它改壞。

但若這個程式 有遵循 TDD 的法則,你隨時都會有個安全機制 :

提醒你程式改壞,還是程式改好

003-3.good

因為你不在害怕,你就會開始動手整理,而不會:

「放任程式碼劣化而視若無睹」

文件

在使用第三方的框架時,可以使用 TDD 來測試程式的行為

003-4.good

這種用「單元測試」堆砌起來的範例,就會是一種比「使用手冊」,更好的「文件」。

003-5.good

因為,這個「文件」,是用程式碼實際描述的,你會更加清楚,每一個涵式與參數的用途。

當有新的版本時:

執行一次單元測試,能很快地發現不一樣的地方。

設計

由於 TDD 的流程,使得「產品程式」不會制約「測試程式」

003-6.good

但「測試程式」卻能制約「產品程式」

003-7.good

它會逼迫你在撰寫「產品程式」時,必須要將函式與其它函式進行解耦合,才能通過測試的要求。

無形中,會讓你去思考:

「如何設計」

JUnit 示範

Intellij + JUnit

這邊使用 IntelliJ 加上 Java 單元測試的 JUnit 框架簡單示範

004-1.demo

需求

現在假定,要開發 Domain 層的一個服務 :

服務名稱叫 AppInfoService

實作的功能 :

判定應用程式的版本,是不是最新的

第一法則: 在撰寫一個單元測試前,不可撰寫任何產品程式

依據這個法則,稍微變通一下。先創建「服務介面」與「實作類別」:

AppInfoService
004-2.demo
interface

AppInfoServiceImpl
004-3.demo
class


先命名功能方法

AppInfoService
004-4.demo

AppInfoServiceImpl
004-5.demo
implements

只做這些,應該還不會偏離法則太遠

創建完類別後,創建單元測試類別

004-6.demo

(IntelliJ 快捷鍵 : cmd + shift + T )

IDE 會自動依據 package 名稱,放置在 test/ 資料夾中

004-7.demo

第二法則: 只撰寫剛好無法通過的單元測試,不能編譯也算無法通過

004-8.demo
單元測試失敗

(IntelliJ 快捷鍵 : control + shift + R )

第三法則: 只撰寫剛好能通過當前測試失敗的產品程式

004-9.demo
撰寫產品程式


004-10.demo
單元測試成功

(IntelliJ 快捷鍵 : control + shift + R )

如此,就完成了一個循環,後續如果還有更複雜的功能。也是透過這種循環快速開發。


測試框架

JUnit 是 Java 的 單元測試框架,其他的程式語言也有各自的測試框架。

例如:

  • 網頁的 JavaScript 有 QUnit
  • iOS 的 Swift 有 XCTest

這三個是我有用過,並且稍微整理成一個專案的:


違反直覺的力量

測試驅動開發的三大法則,是不是覺得字有點多難以記住。

你可以簡單的精簡為 :

先測試,後程式
  • 順序顛倒 : 第一個重點
  • 頻繁執行 : 快速的原因

順序顛倒

這個思維模式,讓我想到 「文件」(開發文件),也是一個很重要的東西。

那麼,程式開發的流程是不是也可以變成 :

文件 > 測試 > 程式 

如此的順序執行呢? (我還在研究的問題...)


違反直覺

測試驅動開發,只是個簡單的思維轉變,就能夠帶來如此巨大的力量。

當你的主管發現你,開發的速度超快,錯誤率又超低的時候。

你可以跟他說 :

這個就是「違反直覺」的力量

其他還有更多「違反直覺」的事情 :

「休息是為了走更長遠的路」(需要更多的放風時間 !)
「安靜是種力量」(PM/SA 沒事,不要那麼常跑來找我 | 你說越多,我可能會開發的越慢 !)

語錄

工程師經驗

拆牆容易,砌牆難
	
     -- Gamma Ray Studio

參考資料

  • Clean Code 無瑕的程式碼 - 敏捷軟體開發技巧守則
  • The Clean Coder 無瑕的程式碼 番外篇 - 專業程式設計師的生存之道

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言