Happy Path and Unit Test
測試金字塔
是很多書、很多演講都會提的概念,從上到下是 E2E、Integration、Unit Test,佔比也是這個次序。
很多大神、知名的軟體教練、傳教士、訪間的訓練機構也都一再強調 Unit Test (以下簡稱 UT) 的重要,經過幾年的宣導與討論,基本上,現在很多軟體工程師都自己會先做 Unit Test,或者在跑 Scrum 時都有出現 Task 內容是要做 Unit Test。對於整個軟體產業而言,是個很好的現象。
這年代跑 Scrum 也越來越普遍,大家也有意識到一個 Scrum Team 就是在做一個產品,大概就像 天龍特攻隊
(A Team) 、或者是阿湯哥 不可能任務
、或者一個 搖滾樂團
,都是 Team Work,理論上,要交付的是一個共同的價值。
Unit Test 不重要?
最近我在工作時,反覆的跟同仁講一段事情:
我同意 Unit Test 很重要,
但是如果東西交到使用者手上的 Happy Path 不能跑,
那做了這麼多 Unit Test 就很可惜。
講的過程,我盡量把用詞修飾的比較不會有太大衝擊,因為普遍工程師已經接受傳教士的說法,避免誤解成:
- Rick 說我的 UT 都在做白工 QQ…
- 是 Rick 叫我不要寫 UT 啊
而我講的重點就在於 次序
、循環
:
- Happy Path 要
先
能動然後
,把 Unit Test 補齊
如果先把 UT 做到 100% 涵蓋率,但是 Happy Path 一個都不能跑,這表示什麼?這個產品不能用,而且死線就在哪裡。
但如果一開始先讓 Happy Path 能跑,跑法可能很髒、很醜、很蠢 … 都沒關係,過程中持續補齊 UT、然後持續修補 Happy Path 的跑法。最後 UT 不管有沒補完,Happy Path 依舊可用的,次序與循環都有了。
案例一:非功能性的 Happy Path
第一個案例是一個專案在即將上線的一前一週,早上站立時,同仁反映應用程式放到 K8s 跑不起來,問題可能是一些 lib 依賴衝突造成的,但是本機跑不會有這樣的問題。
經過一些討論與嘗試,幾天後問題找到暫解法。姑且不論技術問題,算是暫時把部署到 K8s 的狀況解除。說明過程,我刻意把技術問題淡化,而強調 發現的難度
與 發現的時間點
。
後來我跟同仁說我對這件事情的看法:
- 這個技術問題 (依賴 Lib) 本身問題不大,只要給你們時間,很快就能解決
- 這個問題如果可以早一點發現會比較好,因為不難發現
我帶出一個觀念,是我自己想的一段口號:
Deliver Hello World in First Day
在這篇文章 “Version Control 與 Artifact Management“ 有提到這個觀念。
案例二:功能性的 Happy Path
延續案例一,好不容易推上 K8s 了,登入系統後,發現功能全部都不能動 … 又是一個同樣的案例:
我的電腦可以跑、你的電腦不能動
這次是 功能性 (Functional)
的,案例一則是 非功能性 (Non-Functinal)
的,然後明天就要上線了。
背後技術問題是:使用新的前端技術,無法正確讀取 config。同樣的,大家又一起討論,找了一些 Workaround,先把問題處理掉。
同樣的延續案例一,跟大家分享了我的看法:
- 這個技術問題 (前端取得 config) 本身問題不大,只要給你們時間,很快就能解決
- 這個問題如果可以早一點發現會比較好,因為不難發現
(copy and paste … XD)
案例三:示範給大家看
案例一、二發生後,我跟大家分享我對整件事情的看法,過程中其實我心裡有點掙扎的事,要不要說這些話。後來我還是覺得應該要講,而且是對全 Team (about 20)
我說完這段想法之後,不要光說不練,所以親自下去做了幾件事情,我挑了手上六條線的專案中的一項,快速確認 Happy Path 能跑、怎麼跑、有哪些東西缺乏的,不用三十分鐘,開出四、五張 defects
這些問題差不多:
- 你的電腦可以跑,我的電腦不能跑
- 最基本的 Path 跑不起來
(這次就不 c & p 了)
定義 Happy Paths 與交付
我個人定義的 Happy Path 有幾個 必要的限制
,或者說 條件
:
1) 一定是透過 Artifact 跑起來
- 避免你的電腦可以跑、我的電腦不能跑
- Build Process 是正常的
- CI 這段要先做到,後面的程序才有意義。
這段是我定義的 交付
,不是虛的那種價值交付,而是實體軟體檔案的交付。任何軟體開發、軟體工程,最後都需要把東西叫給下一棒,不管是內部的工程師、還是外部客戶、還是後面的自動化程序。Artifact 就是標準的交付介面。有了這段,才有後使用上的價值可言。
2) Happy Path 一定是 黑箱測試
,先驗證應用程式的 內聚力
- 假設 App 功能還沒好了,重點在於驗證 功能正確性,強調的是 App 的
內聚力
。- 熟悉 UT 的人應該可以感覺到這段話的核心思想,與 UT 是一樣的。
- 這個階段
不處理
外在環境因素 (非功能),像是放到 K8s or Cloud / DB HA / 網路架構 / Cache … etc.- 只要有個標準就好,像是透過 docker 跑起來、或者 binary 跑起來即可。
測試策略
的內聚力與耦合性
概念,參閱 系統測試的三兩事 介紹。
3. Happy Path 是 UAT 的其中一環
- UAT 的目的是出貨前要做的驗證,包含 Happy Paths 與 Regression 的項目
- Happy Path 包含功能與非功能的部分,非功能的就是 Artifact、功能性的就像登入、註冊 … 這些基本功能
測試金字塔 該怎麼落實?
回到一開始的金字塔,問題要改成:
怎麼落實、怎麼執行測試金字塔的概念
做軟體開發的公司千百家,但是可以稱得上是 軟體公司 的,可能為數不多,大多都是專案驅動 (死線驅動 DDD),產品驅動較少,重視軟體工程就更少了。
我自己待過很大的國際級軟體公司,走過理想的金字塔;也待過從無到有的新創公司,面對過實際的狀況, (故事放在 這篇文章 的最後一段),但是這兩種公司在軟體開發最後都有一樣要面對問題:
- 內部怎麼認定這東西是好了?
- 怎麼把東西交到客戶手上?
- 客戶怎麼用這個東西?
- 產品對客戶真的能夠提供價值?
能動了,利用 Unit Test 有效的保護各個 function / module 的邊界,反覆修正 Happy Paths 的執行效能,有了這樣的循環,金字塔自然會成行。
而這個概念,根 UT 一開始的概念不是一樣?先不寫功能,先寫測試,然後把每次跑測試的錯誤,一一修復,最後修完,也代表功能寫好了。只是 UT 處理的是顆粒度較小的 function,而 Happy Path 處理的是整個 Application。
所以我認為落實金字塔的方法就是:
建立 UT 與 Happy Path 的循環,
驅動這個循環的則是 Happy Path。
起點是 Happy Path,過程則透過 UT 補強。對應到 金字塔,Happy Path 是 E2E 和 Integration Test。
註: 整合測試
的概念請參閱 “淺談軟體測試的階段與策略“ 的摘要
測試金字塔是萬用的?
其實實際的問題是這個:
- 這個金字塔式萬用的嗎?比例是這樣嗎?UT > Integration > E2E??
- 每個
產品
都可以用這個概念套嗎?做 IoT、做電商、做 API Product 、做網通產品、基礎架構產品 需要的層次不一- 產品在不同階段 (Prototype, Early Stage, 驗證階段, 成長期, 成熟階段) 需要的
策略
不一樣。
這是很弔詭的問題,這個問題大家要放在心裡,別掉進:手上打著錘子,看到啥都是釘子
的圈套。