{%hackmd DfWYF9cYREebVNN1eEOz-w %} 單元測試的藝術 Round3 :ok_hand: ====== ###### tags: `unittest` `書` `單元測試的藝術` `單元測試的藝術 In Python` `202112` > ***不知自己不知道, 那你會以為你知道.*** 此篇前言 ------ 其它章節: [round 1=> link](https://hackmd.io/@GoldxTree/Hyi2nVuNt) [round 2=> link](https://hackmd.io/@GoldxTree/H1v35SGPF) 此篇程式碼範例用跟書中不同語言跟工具做實現, 主要想摸點新玩意:v:, 讓大腦活動活動. 內容多數都會帶入個人觀點去做紀錄. - 環境: - 語言: Python 3.9.7 - 測試工具: pytest-6.2.5 - plugins: mock-3.6.1 # chapter9 在組織中導入單元測試 ## 逐步成為導入變革的領頭羊 9.1 - 想成為組織中變革的領頭羊, 人們都會認為你應該對發生的事情負責 - 必須有人得擔起責任, 確保變革不會缺乏動力而失敗 ### 說服組織內成員: 支持者和反對者 9.1.2 - **想想誰能幫助你, 誰會是阻礙者** - 支持者 - 找出支持者, 通常是擁抱改變的人 - 先去聯繫他們, 請他們對你要做的事情提供意見. - 讓他們做好準備 - 確保他們成為過程的參與者(**因人們若參與其中, 會更願意支持這個過程**) - 讓他們變成你的支持者, 請他們協同你克服反對的聲浪. - 反對者 - 找出反對者, 可從利害關係去思考. 也可能是擔心失去工作或者不想從習慣中跳脫出來. - 高談闊論哪些事情他們應該可以做得更好, 通常不會有效果.(**人們不喜歡別人告訴他們有哪些事情做得不好**) - 試著將單元測試推銷給他們 - 賦予他們新的責任, 他們會覺得自己受到肯定. - 說服高層與管理者 - 必須告知他們, 儘管他們可能不認同 ### 找到切入點 9.1.3 - 選擇較小的團隊 - 通常往往經驗少的成員, 往往更願意接受變革 - 詢問他們是否願意進行一個先驅專案 - 告知目標與願景並進行討論 - 建立子團隊 - 在現有的團隊中, 建立一個子團隊 - 子團隊負責為該專案的痛點建立測試, 比如某些容易產生 bug 的程式或者需求經常調整的功能. - 考慮專案可行性 - 先有一個簡單專案與一個複雜專案分別作為入門磚. - 團隊再幾經失敗後, 至少能看見成功的曙光. - 不能只有無止境的挫折與失敗, 至少最後專案是要能成功的. - 使用程式碼和測試審查作為培訓工具 - 面對面的進行審查, 能夠更好傳遞大量的資訊. - 最初幾個星期, 審查專案簽入的每行程式碼. - 審查必須有通則, 且經過討論的產生的規則. - 避免只有少數幾個人能負責審查, 讓他們在審查的過程去訓練其他人.(**除了平均工作量並更好分配量能外, 另外能讓他們承擔更多責任**) ## 成功之道 9.2 - 從下而上的推動(一般公司不建議這麼做, 需考慮公司文化與制度) - 從上而下的推動(建議這麼做) - 引入外援(比如顧問) - 顧問更可以直接點出, 公司內部不方便說的話.(**程式碼完整性很差、測試可讀性很差... 等等**) - 通常經驗豐富 - 專職的時間 - 顧問是專職的, 公司的員工通常還有別的事情要做.(**公司必須還是得有領頭羊與支持者**) ### 讓進度可見 9.2.4 - 要持續將變革的進度與狀態, 相關資訊進行可視化. - 正在進行變革的族群: 可以從可視化資訊中, 獲得成就感. 並且有讚揚的性質. - 可能讓組織中未參與變革的人產生興趣 ### 設定具體目標 9.2.5 - 如果沒有目標, 就很難衡量變化. - 可以提高測試程式覆蓋率(運用可視化工具) - 糟糕的測試也能提高覆蓋率, 但謹記這些測試最後只會帶來失敗. 不如不要做. - 提高測試覆蓋率通常能越早發現 bug, 減少開發完成後的 bug - 降低修復 bug 後又產生另外 bug 的機率 - 隨著良好的覆蓋率提高, 降低修復 bug 的平均時間 ### 應對阻礙 9.2.6 - 阻礙大多來自於內部, 要謹慎處理. 可以的話應採用心理學的角度去處理. - 對管理層做出承諾 - 碰到挫折或失敗要先理順原因, 並且調整狀態繼續出發. 尤其是領頭羊與支持者. - 設定一個堅持的區間, 比如堅持三個月後能看到那些成果. 並且告知管理層並設法取得他們的認同. ## 失敗原因 9.3 - 缺乏驅動力, 可以借助外部的力量. 比如顧問...等 - 缺乏高層相關政策的支援 - 糟糕的實現和第一印象: 如果在開始階段過於倉促進行單元測試, 會忙手忙腳導致初期導入效果不佳.(**建議至少要知道如何撰寫測試, 並且與支持者已經擬定大致的方向**) - 缺少團隊支持: - 至少要得到部分團隊的支持 - 努力讓團隊融入變革 - 不要將團隊的支持視為理所當然, 要清楚自己的權責. ## 影響因素 9.4 本書列出六個影響因素: ||| | ----------------- |:-----------------------| | 個人能力 | 這個人掌握了執行這項工作的知識或技術嗎? | | 個人特質 | 這個人喜歡把事情做對嗎? 遇到困難能堅持嗎? | | 團隊能力 | 這個人是否獲得了所需要的幫助、資訊、資源? 尤其在關鍵時刻 | | 團隊風氣 | 這個人的周圍是否鼓勵正確行為, 反對錯誤行為. 是否有規則可遵循? | | 組織環境 | 是否有資源與預算, 讓變革更為方便與順利? | | 組織政策 | 是否有相關的政策(包含好與不好的), 讓變革更加順利或者更加困難? | 依據六因素舉例情境: (因人、團隊、組織而異) ||| | ----------------- |:-----------------------| | 個人能力 | kevin 有這個能力, 並且給相關人員進行培訓. | | 個人特質 | kevin 有, 並且支持專案中導入單元測試. | | 團隊能力 | 有! 領頭羊與相關支持團隊, 可相互輔佐與支援. | | 團隊風氣 | 領頭羊與相關人員, 在先前就已討論好了. 現在從專案中實踐 | | 組織環境 | 團隊沒有預算購買因自動建置所需要的機器 | | 組織政策 | 專案經理覺得變革再浪費時間, 並提出若提前交付低品質產品, 能獲得獎金 | ## 質疑和回答 9.5 :::info **通常人們提出問題, 代表變革對他們不利** 以單元測試來說專案經理會擔心時程延宕、QA 擔心自己的工作受到威脅、不想改變現有習慣的人們. ::: ### 現有流程加入當圓測試需要增加多少時間? 9.5.1 - 專案經理和客戶是最關心時程的人, 所以通常會提出疑問 #### 以下度量指標用來判斷這個先驅專案是否成功: - **團隊花在每個開發階段的時間** - **專案交付給客戶的整體時間** - **交付後客戶發現的 bug 數量** - **與先前或另外一個專案來做比對** | 階段 | 不進行單元測試 | 進行單元測試 | | --- |:------------ |:---------- | | 開發天數 | 7天 | 14天 | | 整合 | 7天 | 2天 | | 測試和bug修復 | 12天 | 7天 | | 整體交付時間 | 26天 | 23天 | | 客戶發現的 bug | 71個 | 11個 | :::info - 導入單元測試的專案經理最初並不會認為先驅專案成功, 因為他們只把開發階段納入衡量標準. - 可以強調雖然單元測試增加了開發時間, 但提昇了程式碼可維護性與品質, 使產品的整體交付週期得以縮短. ::: ### 單元測試是否會搶了 QA 飯碗? 9.5.2 **並不會因為還有整合測試與 UI 測試.** ## 小結 將來某個時候都可能需要在組織中進行變革. 不管是否為單元測試. **變革本來就夾帶著風險與阻礙(尤其是人), 不要疏遠了可能幫助自己的人, 準備好進行一場艱難的戰鬥並善用影響力的力量.** # chapter10 遺留程式碼 本章內容: - 探討遺留程式碼常見的問題 - 決定從哪裡開始測試 - 介紹處理遺留程式碼可用的工具(跳過) 此書作者曾經為某間軟體公司提供過顧問服務, 下列描述情境: - 顧問幫助幾個部門學習測試驅動開發 - 但由於各種原因最後仍然有 90% 的人沒有使用測試驅動開發, 原因如下 - 很難給已存在的程式碼撰寫測試 - 幾乎無法重構程式碼, 或者說沒有時間. - 有些人不想修改設計 - 工具使用不便 - 難以決定從什麼地方開始測試 ::: info *上述的情境如果是曾經有過在舊有系統上增加測試的人都知道, 就有系統是無法直接進行單元測試的撰寫, 可能因設計上沒有 DI 所以導致無法抽換依賴.* **測試和修改遺留的程式碼需要處理以下問題:** - 很多工作要做, 但應該從哪裡開始增加測試呢? - 如果系統沒有測試, 要如何安全的重構程式碼呢? - 測試和修改遺留程式碼, 可以使用什麼樣的工具呢? ::: ## 從哪裡開始加入測試 10.1 ### 假設你要測試舊有組件, 那麼需先建立這些組件優先級列表. 影響優先級的因素如下: - **邏輯複雜度:** 組件中的邏輯數量, 例如巢狀、遞迴...等. 可以使用檢查循環複雜度(cyclomatic complexity)得工具來協助判斷. - **依賴程度:** 依賴其它組件的數量 - **優先級:** 評估組件在專案中的優先等級 #### 對以上的因素可以給每個組件列出 1 ~ 10 的優先等級進行評估(表10-1): | 組件 | 邏輯複雜度 | 依賴數量 | 優先級評估 | 備註 | |-----|----------|---------|-------|-----| | Utils | 6 | 1 | 5 | 依賴數量少,且包含很多邏輯。**容易測試且很有測試的價值** | | Person | 2 | 1 | 1 | 一個資料類別,邏輯簡單且依賴少。**有一點測試價值** | | TextParser | 8 | 4 | 6 | 邏輯複雜且依賴多,又是專案中較核心的組件。**所以很有測試的價值,但難度高且費時** | | ConfigManager | 1 | 6 | 1 | 讀取實體檔案並保存設定的組件,邏輯少但依賴很多,**所以測試價值較低, 且測試難度高也費時.** | - 依據 表10-1 可以建立可是化呈現組件的邏輯複雜度和依賴數量(圖10-2) - 可忽略那些低於標準邏輯複雜度標準的組件(作者設定 2~3) - 以 圖10-2 來看就只保留上半部的組件 - 要決定要先測試的組件, 基本上有兩種方式(圖10-3) - 選擇複雜度較高但容易測試的(左上) - 選擇複雜度較高且較難測試的(右上) - 以上兩者皆可, 就是依經驗或需求有不同的選擇.  #### 依據 10-1, 10-2, 10-3 決定選擇策略 - 先易後難的優缺點 - 適合沒有單元測試經驗的團隊 - 起步容易但隨著時間推移, 剩下的組件會越來越難測試. - 對於這樣的團隊, 作者認為初期可以避免依賴數量為 4 的組件. - 先難後易的優缺點 - 適合有單元測試經驗的團隊 - 起步時需要花較多的時間才能看到成效, 但隨著時間推移速度會未來越快 ### 在重構前撰寫整合測試 10.3 - 單元測試不等於整合測試, 就算單元測試覆蓋率 100% 也一樣 - 整理現有的測試情境並列出清單, 且規劃自動化的整合測試.(最笨的那種按一顆紐跑測試, 也是解決問題的好方法) - 有了整合測試, **再重構程式時盡量每次只做少量的修改. 盡可能地每次修改後就執行整合測試. 確保系統功能是否遭到破壞.** ## 小結 - 怎麼知道引入測試如何下手? 請先將各個組件的優先評估清單整理出來 - 團隊有無單元測試的經驗, 會影響一開始選擇組件的標準. - 若不想對進行重構而直接進行單元測試, 也有些工具可以使用. 這些工具能置換執行階段在記憶中的參照物件. # chapter11 設計與可測試性 這個章節主要討論**物件導向設計**與**可測試程式設計**對於軟體的好壞, 作者知道這個話題有很多派人有不同立場. 所以這裡只紀錄某些要點. 對物件導向有興趣的可看看 [物件導向個人心得2](https://hackmd.io/@GoldxTree/ryxspYQWt) ------ ## 可測試性的常見特徵與要點 - 除了一般使用者外, 有另一個使用者是對軟體是測試有所需求. - 最基本的要求就是: 可測試性; 通常大部分的影響會使軟體設計變得更好 - 單元測試具有 FICC 特色: - Fast 執行速度快 - Isolated 相互隔離: 指的是每個測試是獨立的 - Configulation-free 不須額外進行設定 - Consistent 穩定性: 產生穩定可靠的測試結果 - 可測試性的軟體通常滿足 OCP、DIP、IoC/DI 這些物件導向原則. - 避免在包含邏輯的方法中, 初始化具體類別. - 避免直接呼叫靜態方法 - 靜態方法如果需要隔離的話將難以置換 - 可透過前面的章節來解決 [chapter 3 透過虛設常式解決依賴問題](https://hackmd.io/@GoldxTree/Hyi2nVuNt#chapter-3-%E9%80%8F%E9%81%8E%E8%99%9B%E8%A8%AD%E5%B8%B8%E5%BC%8F%E8%A7%A3%E6%B1%BA%E4%BE%9D%E8%B3%B4%E5%95%8F%E9%A1%8C) - 避免在建構式中包含邏輯程式碼 - 需要用單例模式時把單例邏輯獨立出來 - 勢必會增加工作量, 但可讓你能替 API 的使用者考慮更多. - OOP 與可測試設計 兩個是不同情境需求下所生成的概念. - 當你的程式可測試, 不代表就擁有 SOLID 設計. - 這裡舉了一些例子, 有些語言可以於執行時期去動態置換任何東西 - 先前提到的不受限隔離框架, 也可以用於靜態語言中 ## 小結 - 追求好設計有很多不同的切入點 - 可自動化測試的軟體追求的是: - 正式產品減少 BUG - 修改程式碼的過程中保持信心 - 減少維運的工作量 - 長遠來看更少的投入成本 ***本書大致上的內容說得差不多了; 同學們外面的世界還很大, 讓你的人生旅途更加精采.***
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up