剛開始接案的時候,常常為了能趕在結案日來臨之前把案子結掉,很多功能都是表面上能運作就拿去交差,心裏雖然知道可能會有問題,但總是會抱持著賭一把客戶不會發現的心態,就這樣請他們測試驗收,十次裡面大概有十次都會被發現有問題,從此之後我就發現我完全沒有賭運,乖乖把功能測試到自己有信心時才請客戶驗收。
大部分時間我都是用手動測試,如果要測金流外掛,就是每次手動操作一次結帳流程,選擇該金流後進行結帳,然後看 Log 有沒有噴錯。但如果在結帳時有很多欄位要輸入,或是要測試某些商品組合時,每進行一次結帳測試都會多花 10~30 秒,別小看這些時間,當重複測試很多次累積起來所消耗的時間就會非常驚人。
另外自己常發生改東牆壞西牆的狀況,明明在處理的是 A 功能,做完後也測試過沒問題了,結果卻發現看似毫無關聯的 B 功能壞掉了,而且通常都是等到客戶回報才會知道,這樣不僅讓整個程式碼很脆弱,還會降低客戶的信任感,因此我開始試著導入自動化測試來穩固程式碼。
寫測試的目的不是讓程式自動根除臭蟲,而是能夠及早發現問題所在及早治療。
測試的種類
軟體測試有許多不同的類型,主要目的都是為了可以在正式上線前提早發現問題,避免正式上線後因為這問題而造成損失,常見的測試有以下幾種:
1.單元測試 Unit Test
針對程式裡面的最小單元來進行的測試叫做單元測試,最小單元具體的來說可以是一個函式或是類別中的一個方法,測試的目的在於確保每一個函式或方法回傳的結果是如我們所預期的,以及測試當例外狀況或錯誤發生時,回傳的結果也是在我們預料之內,藉此提早發現風險。
2.整合測試 Integration Test
結合外部資料來進行測試稱之為整合測試,有別於單元測試是要測試最小單元,必須要隔離所有會影響測試結果的外部因素,像是從資料庫取得的資料、從 API 拿到的回傳結果來進行測試,而整合測試就是把這些外部因素拉進來一起測試的方法,確保當這些最小單元組合在一起並引入外部因素後仍然可以正常運作。
3.端對端測試 End-to-end Test
單元測試與整合測試是從工程師的角度來進行,而端對端測試則是模擬真實使用者的行為來進行測試,像是我們自己在做手動測試一樣,只是全部都改為用前端程式搭配瀏覽器來控制使用者的滑鼠點擊、頁面跳轉等行為,如果以 WooCommerce 來說,就是測試使用者把商品加入購物車、輸入結帳資料、選擇金流點選結帳按鈕等流程。
寫單元測試的重點
以投入的成本來看,單元測試是 CP 值最高的種類,因為只是測試最小單元所以執行起來的速度很快,又能預先發現潛在的風險,以下為寫單元測試的大原則:
單元測試的命名「要」清晰易懂
可以直接從名稱中辨識這個測試的目的是什麼,像是我想要測試金流商的加密演算方法是否有正確運作,命名 test_ironpay_generate_sign()
就能很直觀看出來其目的。
單元測試「要」測試 True & False
不僅要驗證資料正確的部分,也要考慮到當傳入不正確的資料時,看被測試對象會如何反應,以及反應結果是否如我們所預期。
單元測試「要」隨手進行
不像整合測試或端對端測試因為需要外部環境的支援所以執行起來會很花時間,單元測試可以每寫完一個方法就立刻進行測試,不管是使用命令列工具還是編輯器的擴充套件都能很方便的隨時進行測試。
單元測試「要」持續維護
理想上當然是希望寫一次就可以永遠堪用,但隨著功能的演變測試也要跟上,不然就失去了寫測試的意義。
單元測試裡面「不要」測試實作細節
因為實作有可能會隨著功能需求的變更而進行修改,這會導致測試類別也必須要跟著修改,測試應該要把目標放在輸出結果的驗證而非實作細節。
單元測試裡面「不要」使用邏輯
如果在測試裡面寫了 if else 或其他判斷語句,會增加測試的變數,測試要維持最單純的資料輸入以及驗證輸出的狀態。
單元測試之間「不要」共用變數
如同上面提到單元測試的目的就是要測試最小單元,所以每個測試都是可以獨立測試運作,有時候我們可能為方便重用測試資料,所以會把測試資料當作變數傳入測試中,但這樣可能會導致測試產生預期外的錯誤,如果真有這樣的需求可以用 DataProvider 來處理。
金流外掛的測試項目
開發 WooCommerce 外掛的好處是內建的函式或方法都已經經過開發人員的測試,使用他們提供的 API 可以減少出錯的機會,所以我們需要測試的項目是我們自行設計的邏輯,以鐵人付外掛為例,請求類別 Request、接收類別 Response 以及工具類別 Utility 就是應該著重測試的地方。
下一篇我們以測試 Utility 類別裡面的三個方法為例,來說明如何在外掛中導入單元測試,以及介紹 VSCode 實用的套件來加速測試流程。