The DevOps Handbook:奠定部署管線的基礎、實現快速可靠的自動化測試
18 Oct 2019本文為 Ch9、10 兩章筆記
- Ch9 Create the Foundations of Our Deployment Pipeline 奠定部署管線的基礎
- Ch10 Enable Fast and Reliable Automated Testing 實現快速可靠的自動化測試
所有的東西都要進版控
版本控制系統(version control)用於記錄系統中檔案或檔案集的所有變更,其中一組變更構成一次提交(commit)或稱為修訂(revision)。每個變更與其中繼資料都會以某種方式儲存在系統中,之後便可進行比對、合併或還原至某個版本。
所有的原始檔與配置文件都要進版控,例如
- 專案程式碼、相依的函式庫、靜態檔案。
- 資料庫相關設定的程式碼。
- 建立環境的一切所需工具和腳本、設定檔。
- 手動或自動測試腳本。
- 程式碼打包、部署等的腳本。
- 需求文件、說明。
- 很多很多等等。
這樣做的目的是
- 簡易快速的建立/重現生產環境。
- 由於自動佈建,因此可避免人為手動的錯誤與耗時。
- 鼓勵開發人員更新環境與程式碼,確保開發過程都能接近生產環境。
- 當問題產生時,能檢視每個可能造成問題的變更。
- 版控可降低回復至前一版或某一版所造成的風險。
- 自動將提交的變更執行自動化測試。只要提交變更,都會執行自動化測試。
- 加強溝通,團隊成員可從從版控中看到變更了哪些東西。
- 從版控中看到團隊成員的貢獻與價值。
成功案例
2009 年一家澳洲大型電信公司在做企業資料倉儲專案時,當時有十個進行中的專案,進度都嚴重落後。只有一個勉強在時程內進入客戶驗收的階段(UAT),最後再花了六個月才完成 UAT,但品質低落。
推測進度落後的原因是 將系統部署到生產環境後才發現問題。也就是說,開發與測試中的程式碼和生產環境相比,只有 50% 是相同的,也就是說,許多因不同環境而修正 bug 的程式碼並沒有進入版控,導致開發環境的準備需要八週(很長)的準備時間才能開始進入開發階段。
為了縮短環境準備的時間,改善為
- 所有的程式碼都必須進入版控(解決變更沒有被記錄的問題)。
- 將環境佈置的過程自動化,以便能精準重建環境(解決手動的錯誤、環境不一致的問題)。
因此原本環境的準備需要八週的時間,就縮短為一天,順利幫助團隊的準備符合交付時程、減少交付成本和各種問題。
版控與自動化佈建環境提供自動化測試的基礎,以下來談如何 建立自動化測試的機制。
提交後就馬上進行自動化測試
程式碼一旦提交後,就執行自動化測試,只有當提交通過自動化測試,才能進行部署。也就是說,自動化測試要能確保此次變更是正確的、能部署的。
這樣做的好處是
- 快速得到回饋與修正:不會等到過了很久以後才在回想要怎麼解 bug。
- 維持較小程式碼的整合量:擁有能讓開發者持續整合和測試的環境,讓開發者能每日整合程式碼到主線,並確保主線上的程式碼一直處於可部署的狀態,降低發佈後的風險。
自動化測試要能快速可靠
- 從關鍵且少量的測試開始累積:避免耗費太多時間人力在非必要的功能上。
- 簡單快速頻繁,就可讓開發者快速驗證與修復:提供開發者類正式環境、提早解決可能在生產環境上出現的問題、確保主線上的程式碼處於可部署的狀態、降低發佈後的風險。
- 避免誤報測試有誤:像是因為 timeout 而導致測試失敗,這就要花更多時間反覆測試、確認問題。因此執行少量、可靠的測試是重要的,勝過大量不可靠的自動化測試,或大量手動測試。
因此要自動化的測試應該是從做可以驗證業務目標的測試、少量、可靠的自動化程式開始,然後持續提升和累積測試案例。
測試的方法有哪些
依照測試速度的快慢,自動化測試可分為以下三種。
單元測試
- 單獨隔離測試每個 method、class 或 function,目的是驗證結果等於開發者先前所設計的,也就是滿足工程師的期望。為了做到有效隔離,通常不會使用真的資料庫,而是 stub。
- 重新定義「完成工作」:不一定是通過測試才會完成工作,「測試覆蓋率」低於某個標準時(例如:低於 80%),就可判定驗證結果為失敗,而沒有完成工作。
- 理想測試金字塔:因為單元測試的速度快,因此應該要能發現愈多錯誤愈好,得到回饋和修正的速度才會快,降低成本。也就是說,如果在驗收測試或整合測試遇到錯誤,應編寫對應的單元測試。
理想上,應花多數心力在單元測試上(最下方)。
圖片來源:The DevOps Handbook
驗收測試
- 測試整個系統,確保每個功能模組正常互動。例如:符合使用者故事的商業性質驗收、正確呼叫 API 等,主要目的是滿足使用者的期望。
- 通過驗收測試後的 build 就可進行手動測試。例如:探索性測試、使用者漸滅測試、整合測試等。
- 與單元測試的差異在於,單元測試是分別驗證個別模組。
整合測試
確保這個應用能在生產環境中與其他應用和服務正常運作,次數愈少愈好,儘量在單元測試和驗收測試發現和解決問題。
讓自動化測試養成習慣
- 不接受沒有經過自動化測試的提交程式碼。
- 先編寫自動化測試:TDD、ATDD。
測試驅動開發 (test-driven development,TDD) 和驗收測試驅動開發 (acceptance test-driven development, ATDD),在寫程式之前先寫測試,步驟為
- 先寫一個 test case 是確保測試失敗的,用來提交用。
- 撰寫程式,確保通過測試。
- 重構、優化程式碼,確保通過所有測試。
TDD vs ATDD
- TDD:使用自動化單元測試來驗證個別模組是否可正常運作。
- ATDD:根據 user story 來定義 acceptance test case,用來驗證系統能完成 user story。例如:End-to-End Testing。
盡量將手動測試自動化
- 手動測試速度慢,自動化測試才能做愈多、發現愈多錯誤。
- 人員能做不能被自動化、價值更高的事情。例如:探索性測試、優化測試流程本身
在測試套件中整合效能測試
效能不佳的問題往往是在整合測試或部署到生產環境中才會發現,為了及早發現效能相關的問題,建議這麼做…
- 將平行運行的驗收測試當成效能測試的基礎,例如:平行執行數千個針對關鍵功能,像是「搜尋」和「結帳」的驗收測試。
- 必須要有比較的基準,因此要記錄上次效能測試的結果並作比對,評估各項效能指標。
在測試套件中整合非功能性需求測試
除了測試程式碼符合預期在生產環境下運作外,也需要測試系統的其他與「品質」相關的屬性,意即「非功能性需求」例如:可用性、可擴展性、容量、安全性等。
當部署管線失敗時拉下安燈索
一但某個提交的程式碼會導致自動化測試失敗或佈建失敗,在這個問題被解決前,系統不允許提交新的變更,並可選擇退回前一個版本。這個「不允許提交新的變更」就是安燈索(andon cord)。
為何需要拉下安燈索?
- 若不拉下安燈索或立即解決問題,就會導致之後難以恢復、無法回到可部署的狀態。
- 範例:某次的提交導致自動化測試失敗或佈建失敗,但沒有人修復;接著有人在這個未修復的版本上又提交程式碼,測試與佈建依舊失敗,這樣會導致複雜化失敗問題,測試的運行也不再可靠,就不會有人再寫測試,沒有測試就會讓之後查找與修復變得更困難…惡性循環。