單元測試
本次簡報全都環繞在單元測試
會牽涉到很多東西………
軟體塑模、單元測試工具/概念
就讓我們先從軟體測試概念著手
圖片來源: https://martinfowler.com/articles/microservice-testing/#conclusion-test-pyramid
測試金字塔
先來想一些單元測試上的問題
為什麼單元測試這麼重要?
可不可以使用其它Testing去取代它?
寫單元測試是不是很花時間?
圖片來源: http://javarevisited.blogspot.tw/2017/01/Top-10-excuses-programmers-gives-to-avoid-unit-testing.html#axzz4ucIRqChB
好忙(盲)呀!
單元測試由誰寫?QA?Developer?
要怎麼開始單元測試?
先從寫出可測試程式開始!
S
O
C
K
(Simple)
(Observability)
(Control)
(Knowledge of
the expected result)
可測試的程式需要具備的特質
單純不複雜。E=mc2
Error = mistake * code2
程式碼可以被取得
執行中間過程的變化
以及最終的結果
程式碼的API符合測試案例的需求
程式碼有較少的
不確定(undetermined)
輸出
參考來源: http://www.ithome.com.tw/voice/88062
程式碼如何達成可測試性
第一步是什麼?
正確的軟體塑模(Modeling)
圖片來源: https://www.slideshare.net/InfoQ/why-bdd-can-save-agile
軟體設計的本質
從現實世界的問題映射成軟體解決方案
切記!映射的過程中,不要失去上下文(Context)
映射其實是一種心智轉換,可以採用試誤法(Try and Error)
快速疊代
映射完成之後,在程式設計時要注意什麼?
參考來源: https://www.linkedin.com/pulse/solid-architecture-design-principles-madhavan-ekanathan/
SOLID原則
Single
Responsibility
Principle
• 每個工作單元
僅擁有一項職
責
Open Close
Principle
• 每個工作單元
皆能輕易擴充,
但不接受直接
修改
Liskov
Substitution
Principle
• 衍生類別能夠取
代基礎類別
Interface
Segregation
Principle
• 針對不同客戶端
僅開發它所需要
的介面(API)
Dependency
Inversion Principle
• 改變呼叫端與
被呼叫端的
相依關係;讓呼叫
端不再受制於被
呼叫端
其實還有另一種手法….
參考來源: http://piotrgankiewicz.com/2016/03/15/cqs-an-easy-yet-powerful-pattern/
CQS(Command Query Segregation)
• Command改變物件狀態,不會直接回傳處理結果
• Query僅取得特定值,不會改變物件狀態
變得易於測試!
CQS並不適用所有場景,有些需求
就是無法套用CQS
除了軟體塑模,要達到可測試性
在實務上需要思考…
圖片來源: https://www.tenlong.com.tw/products/9789864342471
實務上的思維
封裝
接縫
設計
可測
試性
實務
• 限制物件對外提供的服務和資料
• 降低複雜度,提供易用性
• 讓程式碼關鍵部份得以被替換的
設計手法
• 配合Mocking工具在設計上的妥協
• 程式設計符合SOCK原則
開始進入單元測試第二步
先瞭解一堆名詞
參考來源: http://www.iteye.com/topic/1116464
相關專有名詞
Mocking
• 讓單元測試免除
外部服務的干擾
• 常用一些偽造物
件取代外部服務
TDD
• 一種以單元測試
為啟始步驟的開
發方法
紅綠重構
• TDD的執行步驟
• 從測試失敗(紅)
開始
• 撰寫程式碼讓其
通過(綠)
• 重構程式碼
ATDD/BDD
• 以實際需求的
例子為基準,滿
足這個例子為標
地撰寫程式碼
3A
• 撰寫單元測試的
常用格式,分別為:
Arrange/Act/Assert
SUT
• 受測單元,可以是
一個類別或是
一個子系統
Mocking!?
讓你感到困惑了嗎
圖片來源: http://www.dotnetcurry.com/aspnet-mvc/1103/aspnet-mvc-model-testing-using-nunit-moq
Mock的意義
Mocking工具有分兩種:
受限 & 不受限
受限的Mocking工具,幾乎都是免費的….
不受限的功能很強大,但是執行比較慢
以Mocking物件來說,分成兩類型:
Stub & Mock
圖片來源: https://stackoverflow.com/questions/3459287/whats-the-difference-between-a-mock-stub
Mock物件
Stub Mock
• 當測試給予正確的輸入參數,Stub回覆固定的值
• 用於測試預期的SUT運作結果
• 當SUT運行後,判定其內部運作是否符合預期
• 用於測試SUT內部運作的狀況
• 建議少用
Stub實際例子
針對DeserializeFromString方法進行偽造
(忽略輸入參數的變化)
回應的罐頭結果
使用工具: Nsubstitute & FluentAssertions
Mock實際例子
確認是否有被呼叫,及其輸入參數
(輸入參數可忽略或強制指定)
使用工具: Nsubstitute
我懂…Mock看起來很帥..但是請少用
Mock會讓測試程式碼變得不好維護/閱讀
Production Code一有改動,測試程式就要跟著改
來談談單元測試在開發上的一些原則
FIRST原則
Fast
Isolates
Repeatable
Self-validating
Timely
單元測試要盡可能讓它在短時間內執行完畢
測試不該存在相依,不論是單元測試彼此之間,或是受測單元的外部相依
單元測試可以不斷重複執行,在沒修改Production程式碼時,本次的執行結果應與上一次相同
驗證測試是否成功,不需要人工介入
盡可能在撰寫Production程式碼之前,撰寫單元測試程式
週邊
參考資料: http://fluentassertions.com/
週邊工具
FluentAssertions AutoFixture
• 讓斷言變得較為口語化,如同自然語言
• 提供許多好用的判斷相等的API
• 快速產出測試素材(Fixture)
• 資料為隨意資料組合,但是可以客製化資料產製的方式
參考資料: https://github.com/AutoFixture/AutoFixture
單元測試做不到的事
無法測試系統行為!
單元測試不能取代其它測試
其它測試也不能取代單元測試!
在實際軟體開發生命週期中
單元測試扮演什麼角色?
圖片資料: https://www.youtube.com/watch?v=e7X-l0pRhnA
你無法阻止需求新增/異動,而每一次的異動
都將造成架構的腐化,你只能重構來拯救你的
系統
沒有單元測試,重構的成本會讓你卻步!

單元測試