1. 單元測試 ( unit test )
單元測試 ( unit test )除用來測試邏輯演算法是否符合預期外,還承擔著監控程式碼質量的責任。任何時候都可以用簡單的命令來驗證全部功能,找出未完成任務 ( 驗收 ) 和任何因修改而造成的錯誤。它與效能測試、程式碼覆蓋率等一起保證了程式碼總是在可控範圍內,這遠比形式化的人工檢查要有用得多
可以將測試、版本管理工具、以及自動釋出 (nightly build)整合。編寫指令碼將測試失敗結果與程式碼提交日誌相匹配,最終生成報告發往指定郵箱
很多人認為單元測試程式碼不好寫,不知道怎麼測試。如果非技術原因,那麼需要考慮結構設計是否合理,因為可測試性也是程式碼質量的一個體現
寫單元測試本身就是對即將要實現的演算法做複核預演。因為無論什麼演算法都需要給如條件,返回預期結果。這些加上平時寫在 main 裡面的臨時程式碼,本就是一個完整的單元測試用例,無非換個地方存放而已
Testing
-
工具鏈和標準庫自帶單元測試框架,這讓測試工作變得相對容易。關於測試,有以下規則:
-
測試程式碼須放在當前包以“ _test.go ” 結尾的檔案中
-
測試函式以 Test 為名稱字首
-
測試命令 ( go test )忽略以 “ _ ” 或 “ . ” 開頭的測試檔案
-
正常編譯操作 ( go build/install )會忽略測試檔案
-
-
標準庫 testing 提供了專用型別 T 來控制測試結果和行為
-
使用 Parallel 可有效利用多核並行優勢,縮短測試時間
對於測試是否應該和目標放在同一目錄,一直有不同的看法。某些人認為應該另建一個專門的包用來存放單元測試,且只測試目標公開介面。好處是,當目標內部發生變化時,無須同步維護測試程式碼。每個人對於測試都有不同的理解,就像覆蓋率是否要做到 90% 以上,也是見仁見智
Table driven
-
單元測試程式碼一樣要寫的簡介優雅,要做到這一點並不容易。好在多數時候,我們可以用一種類似資料表的模式來批次輸入條件並依次比對結果
-
這種方式將測試資料和測試邏輯分離,更便於維護。另外,使用 Error 是為了讓整個表全部完成測試,以便知道具體是哪組條件出了問題。
Test main
-
某些時候,須為測試用例提供初始化和清理操作,但 testing 並沒有 setup / teardown 機制。解決辦法是自定義一個名為 TestMain 的函式,go test 會改為執行該函式,而不再是具體的測試用例
-
M.Run 會呼叫具體的測試用例,但麻煩的是不能為每一個測試檔案寫一個 TestMain
-
要實現用例組合套件 ( suite ),需藉助 MainStart 自行構建 M 物件。透過與命令列引數相配合,即可實現不同測試組合
Example
-
例程式碼最大的用途不是測試,而是匯入到 GoDoc 等工具生成的幫助文件中。它透過比對輸出 ( stdout )結果和內部 output 註釋是否一致來判斷是否成功
-
如果沒有 output 註釋,函式就不會被執行。另外,不能使用內建函式 print/println 因為它們輸出到 stderr
2. 效能測試
-
效能測試函式以 Benchmark 為名稱字首,同樣儲存在 “ *_test.go ” 檔案裡
-
測試工具預設不會執行效能測試,須使用 bench 引數。它透過逐步調整 B.N 值反覆執行測試函式,知道獲得準確的測量結果
-
如果僅希望進行效能測試,可以用 run = NONE 忽略所有單元測試用例
-
某些耗時的目標,預設迴圈次數過少,取平均值不足以準確計量效能。可使用 benchtime 設定最小測試時間來增加迴圈次數,以便返回更準確的結果
Timer
-
如果在測試函式中要執行一些額外操作,那麼應該臨時阻止計時器工作
Memory
-
效能測試關心的不僅僅是執行時間,還包括在堆上的記憶體分配,因為記憶體分配和垃圾回收的相關操作也應該計入消耗成本
-
也可以將測試函式設定為總是輸出記憶體分配資訊,無論使用 benchmem 引數與否
3. 程式碼覆蓋率
-
如果說單元測試和效能測試關注程式碼質量,那麼程式碼覆蓋率 ( code coverage)就是度量測試自身完整和有效性的一種手段
-
透過覆蓋率值,我們可以分析出測試程式碼的編寫質量。檢測它是否提供了足夠的測試條例,是否執行了足夠的函式、語句、分支、和程式碼行等,依次來量化測試本身,讓白盒測試真正起到應有的質量保障作用。
-
當然,這並不是說要追求形式上的數字百分比。關鍵還是為改進測試提供一個可發現缺陷的機會,畢竟只有測試本身的質量得到保障,才能讓它免於成為形式主義擺設
-
程式碼覆蓋率也常用來發現死程式碼 ( dead code )
-
為獲取更詳細的資訊,可指定 covermode 和 coverprofile 引數
-
set :是否執行
-
count: 執行次數
-
atomic:執行次數 (支援併發模式)
-
還可以在瀏覽器中檢視包括具體的執行次數等資訊
-
4. 效能監控
-
引發效能問題的原因無外乎執行時間過長,記憶體佔用過多,以及意外阻塞。透過捕獲或監控相關執行狀態資料,就可定位引發問題的原因,從而有針對性改進演算法
-