Go單元測試

Go 語言中,單元測試是通過標準庫中的 testing 包來實現的,該包提供了一組功能,使得編寫、運行和管理單元測試變得簡單和高效。

一、規則

  • 測試文件的命名規則
    Go 中的測試文件命名規則是在被測試的源文件名后面加上 _test.go。例如,如果你有一個 calculator.go 文件,相應的測試文件應該是 calculator_test.go

  • 測試函數的命名規則
    測試函數必須以 Test 開頭,后面可以跟任何非空字符串,例如 TestAddTestSubtract 等。

  • 使用 testing.T 進行斷言和錯誤報告
    在測試函數中,使用 testing.T 類型的參數來管理測試狀態和輸出。你可以使用 t.Error*t.Fail* 等方法來指示測試失敗,并輸出相關的錯誤信息。

二、單元測試示例

2.1 單個測試用例

在calculator包中定義了一個calculator函數,具體實現如下:

package calculatorfunc Add(a, b int) int {return a + b
}

在當前目錄下,我們創建一個calculator_test.go的測試文件,并定義一個測試函數如下:

package calculatorimport "testing"func TestAdd(t *testing.T) {result := Add(1, 2)expected := 3if result != expected {t.Errorf("Add(1,2) return %d, expected %d", result, expected)}
}

要運行這個單元測試,可以使用 go test 命令。在命令行中進入到包含 calculator.go 和 calculator_test.go 的目錄,然后執行go test,這些結果如下

go test
PASS
ok      modu    0.226s

2.2 多個測試用例

在calculator_test.go中添加如下測試函數:

func TestAdd2(t *testing.T) {result := Add(3, 2)expected := 3if result != expected {t.Errorf("Add(1,2) return %d, expected %d", result, expected)}
}

為了能更好的在輸出結果中看到每個測試用例的執行情況,我們可以為go test -v參數,讓它輸出完整的測試結果。

go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2calculator_test.go:17: Add(1,2) return 5, expected 3
--- FAIL: TestAdd2 (0.00s)
FAIL
exit status 1
FAIL    modu    0.216s

2.3 指定運行測試用例

go test -run 命令可以按照指定的模式運行測試。這個命令支持通過正則表達式來選擇要運行的測試函數。

例如修正好TestAdd2用例之后,通過go tes -run=Add2只運行TestAdd2這個測試用例,結果是

go test -run=Add2 -v
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
PASS
ok      modu    0.198s

4. 跳過某些測試用例
新加測試函數

func TestAdd3(t *testing.T) {if testing.Short() {t.Skip("short模式下會跳過該測試用例")}result := Add(3, 2)expected := 5if result != expected {t.Errorf("Add(1,2) return %d, expected %d", result, expected)}
}

當執行go test -short時,就會跳過testing.Short()標記的測試用例,結果是

go test -short -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN   TestAdd3calculator_test.go:23: short模式下會跳過該測試用例
--- SKIP: TestAdd3 (0.00s)
PASS
ok      modu    0.635s

三、測試組和子測試

3.1 測試組和子測試

通過測試組和子測試,可以更友好來添加更多的測試用例,以及查看結果

func TestAdd(t *testing.T) {tests := []struct {name     stringx, y     intexpected int}{{"Add1", 1, 2, 3},{"Add2", 3, 3, 6},{"Add3", 4, 5, 8},}for _, tc := range tests {t.Run(tc.name, func(t *testing.T) {result := Add(tc.x, tc.y)if result != tc.expected {t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)}})}
}

運行go test -v,結果是

go test -v
=== RUN   TestAdd
=== RUN   TestAdd/Add2
=== RUN   TestAdd/Add3calculator_test.go:51: Add(4, 5) returned 9, expected 8
--- FAIL: TestAdd (0.00s)--- PASS: TestAdd/Add1 (0.00s)--- PASS: TestAdd/Add2 (0.00s)--- FAIL: TestAdd/Add3 (0.00s)
FAIL
exit status 1
FAIL    modu    0.190s

3.2 并行測試

Go語言天生支持并發,所以通過添加t.Parallel()來實現驅動測試并行化。

func TestAdd(t *testing.T) {t.Parallel()  // 將 TLog 標記為能夠與其他測試并行運行// 這里使用匿名結構體定義了若干個測試用例// 并且為每個測試用例設置了一個名稱tests := []struct {name     stringx, y     intexpected int}{{"Add1", 1, 2, 3},{"Add2", 3, 3, 6},{"Add3", 4, 5, 8},}for _, tc := range tests {tc := tc  // 注意這里重新聲明tt變量(避免多個goroutine中使用了相同的變量)t.Run(tc.name, func(t *testing.T) {t.Parallel()  // 將每個測試用例標記為能夠彼此并行運行result := Add(tc.x, tc.y)if result != tc.expected {t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)}})}
}

3.3 測試覆蓋率

使用go test -cover來查看測試覆蓋率

go test -cover
PASSmodu    coverage: 100.0% of statements
ok      modu    1.149s

四、Go單元測試工具包 – testify

在進行Go語言單元測試時,由于官方并未內置斷言功能,我們通常需要使用大量的if...else...語句來校驗測試結果。然而,通過使用第三方庫如testify/assert,我們可以輕松地調用多種常用的斷言函數,這些函數不僅能夠簡化測試代碼,還能生成清晰易懂的錯誤描述信息,幫助我們快速定位問題。

在上面例子當中,我們使用if...else...語句來校驗測試結果

	for _, tc := range tests {t.Run(tc.name, func(t *testing.T) {result := Add(tc.x, tc.y)if result != tc.expected {t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)}})}

現在可使用testify/assert之將上述判斷過程簡化如下:

	for _, tc := range tests {t.Run(tc.name, func(t *testing.T) {result := Add(tc.x, tc.y)assert.Equal(t, result, tc.expected)})}

testify/require擁有testify/assert所有斷言函數,它們的唯一區別就是testify/require遇到失敗的用例會立即終止本次測試。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/40254.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/40254.shtml
英文地址,請注明出處:http://en.pswp.cn/web/40254.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

matplotlib下載安裝

matplotlib下載安裝過程同之前寫的pygame很類似。 Pygame下載安裝 python官網 1.搜索matplotlib 直接點進去 查看歷史版本,因為新版本可能出現與python不匹配問題。 我選擇3.6.3版本,因為我安裝的python是3.8,可以匹配版本。同時window操…

Linux文件描述符與FILE指針互相轉換

目錄 1、文件描述符轉換為 FILE 指針 2、FILE 指針轉換為文件描述符 在Linux中,文件描述符(file descriptor, fd)和FILE指針(也稱為文件流指針,FILE pointer)是兩種常見的文件操作接口。文件描述符是一個…

Cesium與Three相機同步(3)

Cesium與Three融合的案例demo <!DOCTYPE html> <html lang"en" class"dark"><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"><meta name"viewport" content&q…

C++ 類和對象 構造函數

一 類的6個默認成員函數&#xff1a; 如果一個類中什么成員都沒有&#xff0c;簡稱為空類。 例&#xff1a; #include <iostream> class Empty {// 空類&#xff0c;什么成員都沒有 }; 空類中真的什么都沒有嗎&#xff1f;并不是&#xff0c;任何類在什么都不寫時&a…

洛谷 P1035 [NOIP2002 普及組] 級數求和

本文由Jzwalliser原創&#xff0c;發布在CSDN平臺上&#xff0c;遵循CC 4.0 BY-SA協議。 因此&#xff0c;若需轉載/引用本文&#xff0c;請注明作者并附原文鏈接&#xff0c;且禁止刪除/修改本段文字。 違者必究&#xff0c;謝謝配合。 個人主頁&#xff1a;blog.csdn.net/jzw…

qt 讀取配置文件

在Qt中讀取配置文件&#xff0c;主要有以下幾種方法&#xff1a; 使用QFile和QTextStream類&#xff1a; 這種方法適用于讀取任意文本文件&#xff0c;包括配置文件。使用QFile的open()方法打開配置文件。使用QTextStream的readLine()方法逐行讀取配置數據。使用QXmlStreamRea…

谷粒商城學習-筆記大全

1&#xff0c;谷粒商城-01-項目介紹 2&#xff0c;谷粒商城筆記-02-項目整體效果展示 3&#xff0c;谷粒商城筆記-03-分布式基礎概念 4&#xff0c;谷粒商城筆記-04-項目微服務架構圖簡介 5&#xff0c;谷粒商城學習筆記-05-項目微服務劃分圖 6&#xff0c;谷粒商城學習-06-使用…

【LinuxC語言】手撕Http協議之accept_request函數實現(一)

文章目錄 前言accept_request函數作用accept_request實現解析方法根據不同方法進行不同操作http服務器響應格式unimplemented函數實現總結前言 在計算機網絡中,HTTP協議是一種常見的應用層協議,它定義了客戶端和服務器之間如何進行數據交換。在這篇文章中,我們將深入探討Li…

C++模塊化之內部類

目錄 1.引言 2.內部類的訪問控制 3.優缺點分析 4.實際運用 4.1.實現復雜數據結構 4.2.封裝細節實現 4.3.事件處理和回調 4.4.模板元編程輔助類 4.5. 訪問控制和封裝 4.6. 代碼組織和模塊化 5.總結 1.引言 在C中&#xff0c;內部類&#xff08;Nested Class&#xff…

力扣爆刷第159天之TOP100五連刷61-65(翻轉單詞、對稱二叉樹、遍歷求和)

力扣爆刷第159天之TOP100五連刷61-65&#xff08;翻轉單詞、對稱二叉樹、遍歷求和&#xff09; 文章目錄 力扣爆刷第159天之TOP100五連刷61-65&#xff08;翻轉單詞、對稱二叉樹、遍歷求和&#xff09;一、151. 反轉字符串中的單詞二、129. 求根節點到葉節點數字之和三、104. 二…

簡單解讀倫敦銀CFD(XAG)走勢圖

從本質上說&#xff0c;倫敦銀是一種差價合約&#xff08;CFD&#xff09;交易&#xff0c;在同平臺所提供的MT4中&#xff0c;它的代碼也許并不一樣&#xff0c;有的平臺會顯示為XAG&#xff0c;有的平臺會顯示為LLS或Silver&#xff0c;但它們指的其實是同一個品種&#xff0…

Python學習筆記29:進階篇(十八)常見標準庫使用之質量控制中的數據清洗

前言 本文是根據python官方教程中標準庫模塊的介紹&#xff0c;自己查詢資料并整理&#xff0c;編寫代碼示例做出的學習筆記。 根據模塊知識&#xff0c;一次講解單個或者多個模塊的內容。 教程鏈接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 質量控制…

基于單片機的防酒駕控制系統設計

摘 要&#xff1a; 酒后駕車的危害十分巨大&#xff0c;因此&#xff0c;筆者介紹了一種基于單片機的防酒駕控制系統。系統由酒精傳感器 MQ-3測量汽車駕駛員體內的酒精含量濃度&#xff0c;通過 A/D 轉換器轉換成數字信號傳給單片機&#xff0c;經過單片機處理后顯示酒精濃度&a…

c++11新特性-6-using

文章目錄 using1.定義別名 using 1.定義別名 1.1 定義類型別名 using t int; 1.2 定義函數指針 int test(double,string){}//返回值類型 int &#xff0c;參數類型&#xff1a;double string using func int(*) (double,string);int main() {func f test;f(10.5,“hello…

算法訓練營day69

查并集&#xff1a;107. 尋找存在的路徑 (kamacoder.com) #include<iostream> #include<vector>using namespace std;vector<int> father(101, 0);void init() {for(int i 1;i < 101;i) {father[i] i;} }int find(int v) {if(v father[v]) return v;e…

老年生活照護實訓室:為養老服務業輸送專業人才

本文探討了老年生活照護實訓室在養老服務業專業人才培養中的關鍵作用。通過詳細闡述實訓室的功能、教學實踐、對學生能力的培養以及面臨的挑戰和解決方案&#xff0c;強調了其在提升人才素質、滿足行業需求方面的重要性&#xff0c;旨在為養老服務業的可持續發展提供有力的人才…

electron教程(二)控制應用程序的事件生命周期

1.will-finish-launching 當應用程序完成基礎的啟動的時候被觸發&#xff0c;在 Windows 和 Linux 中, will-finish-launching 事件與 ready 事件是相同的; 在 macOS 中&#xff0c;這個事件相當于 NSApplication 中的 applicationWillFinishLaunching 提示。 app.on(will-fi…

Butterfly主題文章標題改成轉動小風車

效果 標題級別不同小風車顏色不同&#xff0c;鼠標移入會有轉動變慢及變色效果。 新建css 建議在/source下創建諸如img/css/js等文件夾&#xff0c;存放文章或網站用的素材&#xff0c;分門別類后續也方便維護。 Hexo打包的時候&#xff0c;會自動把/source下的文件&#…

深度神經網絡語言識別

「AI秘籍」系列課程&#xff1a; 人工智能應用數學基礎人工智能Python基礎人工智能基礎核心知識人工智能BI核心知識人工智能CV核心知識 使用 DNN 和字符 n-gram 對一段文本的語言進行分類&#xff08;附 Python 代碼&#xff09; 資料來源&#xff0c;flaticon&#xff1a;htt…