測試驅動開發
Test Driven Development
By 黃升煌
參考資源
• 在國外不認識Uncle Bob就等於不會TDD
 網站: http://butunclebob.com/ArticleS.UncleBob
• 在台灣不認識91哥就等於不會TDD
 課程: https://skilltree.my/events/mbh
 網站: https://www.facebook.com/91agile
 書單: https://91-tdd.hackpad.com/91--SCin8rM6vpI
2
這是一個開發人員小明的故事
如有雷同,純屬巧合
小明是個剛出社會的程式開發人員…
在XX公司擔任系統開發的工作
4
這是小明習慣的系統開發流程…
需求 撰寫程式 手動測試 交付系統
5
工作幾個月後,小明發現自己的工作遇到了一些問題…
6
7
小明常常覺得自己開發系統像無頭蒼蠅
8
寫出來的程式碼感覺總是難以維護
9
辛苦開發出來的系統,總是不太符合user的需求
10
最討厭的是,測試程式好花時間,好不想測
所以乾脆不測或只測一些部分
倒楣的是,bug都剛好發生在沒有測到的部分…
11
主管或user常常質問小明…
你難道都沒自己測過嗎!?
12
小明覺得自己開發系統的工作像這樣…
13
小明不開心
14
不過,小明是有為上進的好青年
所以小明主動開始尋找一些好的測試方法
15
首先,小明找到了
單元測試!(Unit Test)
16
最小的測試單位
與外部資源相依性為零
不具商業邏輯
測試案例之間的相依性為零
一個測試案例只做一件事
小明暸解了什麼是Unit Test
17
Fast:可快速知道結果
Isolated:與外部資源隔離
Repeatable:執行100次100次結果應該都會一樣
Self-Validation:可以直接從測試報表中理解意義或失敗原因
Timely:production code與test code同時存在
小明學到了Unit Test的特性─FIRST
找出要測試的目標(SUT、System Under Test)
18
•初始化SUT需要的相關參數、模擬物件
1. Arrange
•實際呼叫SUT
2. Act
•驗證SUT是否如預期運作
3. Assert
同時,小明也使用3A Pattern來撰寫測試程式
19
Demo一下…
• 一個加法器程式DEMO
• 為加法器加上unit test確保程式正確
20
有了Unit Test之後小明…
有了可以快速驗證程式邏輯正確性的工具
而且在改了A邏輯後,可以立刻知道是否
影響到其他的邏輯錯誤
在想得到的範圍內,加上單元測試,只要
測試都是通過的,小明就可以有信心的說
「在想得到的狀況內,我的程式沒有問題」
21
但是,小明又發現了新的問題
寫完程式碼,卻難以下手撰寫測試案例
當需求異動時,測試案例要不要異動?
常常忘了/懶得要寫測試案例驗證程式,
所以測試覆蓋率低落,改東壞西的Bug
還是常發生(雖然比以前少)
22
還好,小明是有為上進的好青年
所以小明繼續尋找讓測試案例更容易應用在開發上的方法
23
於是,小明找到了
測試驅動開發!
(Test Driven Development、TDD)
24
關於測試驅動開發,小明學到最重要的一堂課是
重點在開發!
重點在開發!
重點在開發!
因為很重要,所以講三次!
Test Driven Development特性
•測試先行
•用測試案例代表需求
•撰寫程式來通過測試案例
•不斷重構,以增強系統架構與可維護性
25
小明學到了TDD的一些特性
26
小明學到TDD的開發流程
需求
撰寫一個
測試案例
執行測試
(紅燈)
針對test case
撰寫程式
執行測試
測試結果為
(綠燈)
重構程式碼
不需要
重構程式碼
是
是否需要重構 是否
撰寫下一個
測試案例
否
27
小明也學到了TDD的三個重要原則
• UncleBob: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
1. You are not allowed to write any production code unless it is to make a failing unit test pass.
 在有一個錯誤的測試之前不應該撰寫任何production code
2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation
failures are failures.
 當有一個失敗的測試案例(編譯錯誤也是錯誤)時,不應該撰寫更多的測試案例
3. You are not allowed to write any more production code than is sufficient to pass the one
failing unit test.
 除了足夠通過測試案例的程式碼以外不應該撰寫更多額外的程式碼
28
開始使用TDD開發後,小明覺得
一次專注在一個測試案例上,更容易專心了
有測試保護程式,能更容易重構程式碼,
程式碼變得越來越好維護
先寫測試案例再開發,測試覆蓋率極高,
改東壞西的bug發生頻率大幅降低!
29
小明覺得很開心
30
直到小明用TDD方式開發完成了第一個系統…
小明才發現
跟人溝通才是開發系統最大的障礙
31
小明想拿測試案例說明自己開發的現況
但是主管/user才不想看到程式碼
32
當需求異動時,雖然有測試案例保護不怕改壞程式
但異動時要修改龐大的測試程式實在好辛苦
33
最慘的是,小明用TDD完成了兩個需求,也通過測試案例
需求如下:
•為了避免上下樓梯學生跌倒,我要在樓梯加裝扶手
•測試案例: 扶手必須是空心金屬管且佈滿邊緣
•為了避免火警,我要在走廊裝設顯眼的滅火器
•測試案例: 滅火器必須放置在牆上且外觀是顯眼的紅色
34
結果開發出來是
扶手必須是空心金屬管且佈滿邊緣
滅火器必須放置在牆上且外觀是顯眼的紅色
35
User的反應
36
主管的反應
37
小明不開心
38
還記得嗎?小明是有為上進的好青年
所以小明繼續尋找
開發時測試案例能和顧客溝通無障礙的方法
39
皇天不負苦心人,小明找到了
行為驅動開發!
(Behavior Driven Development、BDD)
•與專案有關的利益相關者密切合作
•使用同一種語言溝通(人話)
•使用可自動執行的範例描述系統行為
•將人話自動轉成測試程式─人話與測
試程式自動繫結
•活的文件(Living Document)─文件
即需求&測試案例;且可直接從文件
上得到開發進度和測試結果。
BDD如何解決問題?
•可針對需求撰寫測試程式,但並沒有
真的去釐清需求
•測試案例程式碼對developer來說可
以代表需求文件,但對user來說是天
書
•當需求異動時,測試程式難以同步異
動
TDD的問題
40
小明眼中的BDD解決的TDD的一些問題
• 用人話描述需求─Gherkin語法:
Feature: 用一個簡單的故事描述需求
Scenario: 系統行為
Given – Arrange
When – Act
Then – Assert
41
Sample
Feature:
In order to 避免計算錯誤
As a 數學白癡
I want to 知道兩個數字相加的結果
Scenario: 兩個數字相加
Given 在計算機輸入 50
And 按下 + 按鈕
And 在計算機輸入70
When 按下計算
Then 結果應該為 120
在BDD中,用人話搭配Gherkin語法描述需求規格
 動態、不斷修改和更新的文件
 避免逆向工程:從程式邏輯反推業務邏輯是很困難的(說不定程式
邏輯其實還是錯的)
 將文件、業務邏輯、程式邏輯綁在一起
 當需求異動時可以同時更新
 可以用來追蹤開發進度
 其他…
42
這些需求規格,可以變成活的文件(Living Document)
43
小明學到BDD的開發流程
需求
專案關係人共同
討論,說人話並
由實例、雛形產
生需求文件
由文件產生
測試程式
TDD開發
產生
活的文件
44
雖然BDD有許多好處,但是小明也發現…
專案關係人常常都很忙,沒時間聚在一起討論
要正確描述可實行的需求也是要溝通技巧的
需要密切的配合,代表討論需求的成本也高
45
由於BDD進入成本相對較高,於是小明決定
用BDD的精神和TDD的流程進行系統開發
46
當需求出現時,小明
釐清需求並用人話描述需求與規格
可能的話盡量多與專案關係人確認需求
將需求與測試程式自動繫結在一起
針對需求產生的測試程式以TDD的流程進行系統開發
47
使用這樣的流程開發後,小明發現
用人話溝通比用程式溝通輕鬆多了
需求異動時改文件或改測試程式都更容易
當功能開發完成,文件自動更新結果,更容易追蹤進度
48
Demo一下…
• 用人話完成需求規格
• 需求與測試自動繫結
• 測試結果自動更新到文件上
• 透過CI,在每次簽入程式碼時執行測試並更新文件
49
到目前為止,小明的經驗
Unit Test: 確保程式跑起來跟想的一樣
TDD: 先想清楚系統如何運作再寫程式
BDD: 用人話描述需求,將需求與測試繫結,
減少認知差異
TDD/BDD的重點是開發!測試只是順便
帶著測試的心態學TDD會覺得層層阻礙
帶著開發的心態學TDD便能了解其中美妙
將問題拆解成小問題,再一個個解決,開發會更順暢
50
小明很開心!
小明還在持續學習中
以後是否會學到新的方法?
那又是另外一個故事了…
The End
補充:關於UI的自動化測試
這裡講的不是開發,是測試
問題
• 這樣的畫面你要怎麼測?
55
問題
• 手動測試的問題
 N個欄位要手動輸入
 每次測試資料不能打錯
 一點點小修改就要重新測試一次
 需求異動時改程式10分鐘,但測試要多久?
56
自動化測試
57
 Web測試─Selenium
 FireFox外掛
 可錄製操作行為
 可轉成C#測試程式
 WinForm測試
 UI Automation
 官方產品
 https://msdn.microsoft.com/en-us/library/dd286726.aspx
 White
 https://github.com/TestStack/White
 自動化測試
 自動化執行的測試腳本
 做一次,用很多次
 腳本跑完可以自動驗證
結果是否正確
補充: 測試框架
測試框架
• Jasmine: http://jasmine.github.io/2.0/introduction.html
• Chutzpah: https://visualstudiogallery.msdn.microsoft.com/71a4e9bd-f660-
448f-bd92-f5a65d39b7f0
• JUnit: http://junit.org/
• JBehave: http://jbehave.org/
• PHPUnit: https://phpunit.de/index.html
• Behat: http://docs.behat.org/en/v2.5/
59
Q&A

Test Driven Development