Go 語言中的單元測試

1、如何編寫單元測試

在任何生產級別的項目開發中,單元測試都扮演著至關重要的角色。盡管許多初創項目在早期可能忽略了它,但隨著項目逐漸成熟并成為核心業務,為其編寫健壯的單元測試是保障代碼質量和項目穩定性的必然選擇。本文將帶您快速掌握 Go 語言中單元測試的基本方法和核心概念。

1、核心命令:go test

Go 語言的測試工具鏈非常簡潔,其核心是 go test 命令。這是一個依據特定約定來組織和驅動測試代碼的程序。當你在一個包目錄中執行 go test 時,它會自動尋找并執行所有符合測試規范的用例。

2、測試文件的約定

go test 命令的運行依賴于一套簡單的文件和函數命名約定:

  1. 文件名約定:在包目錄中,所有以 _test.go 為后綴的源文件都會被 go test 命令識別為測試文件并執行。
  2. 構建時排除:您無需擔心測試文件會增加最終可執行文件的大小。go build 命令在編譯和打包時會自動忽略這些 _test.go 文件,確保它們只存在于測試環境中。

3、測試函數的類型

_test.go 文件中,我們主要會編寫以下幾種類型的測試函數,目前我們主要關注前兩種:

  • 功能測試 (Functional Tests):函數名以 Test 開頭,例如 TestMyFunction。這是最常見的測試類型,用于驗證代碼功能的正確性。
  • 性能測試 (Benchmark Tests):函數名以 Benchmark 開頭,例如 BenchmarkMyFunction。用于衡量代碼的性能和效率。
  • 示例測試 (Example Tests):函數名以 Example 開頭,用于提供可執行的示例代碼,常用于文檔生成。
  • 模糊測試 (Fuzzing Tests):以 Fuzz 開頭,是一種自動化的測試技術,用于發現邊界條件下的潛在錯誤。

4、編寫第一個單元測試

讓我們通過一個具體的例子來演示如何編寫和運行一個單元測試。

1. 準備被測試的代碼

首先,我們創建一個 add.go 文件,并在其中定義一個簡單的加法函數。

image.png

2. 創建測試文件

接下來,在與 add.go 相同的包(目錄)下,我們創建測試文件 add_test.go。將測試文件和源文件放在同一包內,可以方便地測試包內未導出的(小寫字母開頭的)函數和方法。

image.png

3. 編寫測試函數

add_test.go 文件中,我們編寫一個功能測試函數來驗證 Add 函數的正確性。

測試函數的規范:

  • 函數名必須以 Test 開頭,后面通常跟上被測試的函數名,如 TestAdd
  • 參數必須是 t *testing.T*testing.T 類型提供了報告測試失敗和記錄日志等核心功能。

image.png

編寫完成后,許多 IDE(如 GoLand)會自動在函數旁顯示一個可運行的標記,這表明 IDE 已經識別出這是一個有效的測試用例。

2、管理和跳過耗時測試

當測試用例數量增多時,某些測試(如涉及網絡請求或大量計算的測試)可能會運行得非常緩慢。為了在開發過程中獲得快速反饋,我們常常希望可以跳過這些耗時的測試。

Go 語言為此提供了 -short 模式。

工作原理

  1. 在運行測試時,可以附加 -short 標志:go test -v -short
  2. 在測試函數內部,可以通過 testing.Short() 函數進行判斷。如果 -short 標志被設置,該函數返回 true
  3. 使用 t.Skip() 方法來跳過當前測試。當 t.Skip() 被調用時,該測試函數會立即終止,并被標記為“已跳過”(SKIPPED),而不會被標記為“失敗”(FAILED)。

讓我們添加一個模擬的耗時測試 TestLongRunningTask

.正常模式

執行 go test -v,所有測試都會運行,包括耗時的測試。

image.png

可以看到,總耗時超過了2秒。

b. Short 模式

執行 go test -v -short,耗時的測試將被跳過。

image.png

可以看到,TestLongRunningTask 被標記為 SKIP,并且總耗時非常短。通過這種方式,我們可以靈活地控制運行哪些測試用例,從而提升開發效率。

3、表格驅動測試 (Table-Driven Tests)

當我們需要用多組不同的輸入和期望輸出來測試同一個函數時(例如,測試正常情況、邊界情況、異常情況),為每一組數據編寫一個獨立的 Test 函數會非常繁瑣且難以維護。

表格驅動測試模式優雅地解決了這個問題。其核心思想是將所有測試用例定義在一個“表格”(通常是一個結構體切片)中,然后在一個測試函數內遍歷這個表格,執行每一個測試用例。

實現步驟

  1. 定義測試用例結構體:創建一個結構體,用于描述一個完整的測試用例,包含輸入參數和期望的輸出結果。
  2. 創建測試用例表格:聲明一個該結構體的切片,并填充所有需要測試的數據。
  3. 遍歷表格執行測試:在測試函數中,使用 for 循環遍歷切片。對于每個測試用例,執行被測函數并斷言結果。
  4. (推薦) 使用 t.Run 創建子測試:在循環中為每個測試用例創建一個子測試。這樣做的好處是,所有測試用例都會被執行(即使中途有失敗),并且測試結果會清晰地分組展示,便于定位問題。

代碼示例

讓我們用表格驅動模式來重構 TestAdd

image.png

當我們運行這個測試時,如果出現錯誤(例如,我們將第三個用例的期望值 expected 錯寫成 0),會得到非常清晰的報告。

image.png

這個輸出明確地告訴我們,只有名為 input:_-9,_8 的子測試失敗了,極大地提高了調試效率。

4、性能測試 (Benchmark Tests)

除了功能正確性,代碼的性能也是衡量質量的重要維度。對于一些位于核心路徑、對性能有高要求的函數,我們需要進行性能測試。Go 語言內置了強大的性能測試框架。

性能測試的規范

  • 函數命名:性能測試函數必須以 Benchmark 開頭,例如 BenchmarkAdd
  • 函數簽名:參數必須是 b *testing.B*testing.B 類型提供了控制計時器、設置迭代次數等能力。
  • 核心循環:測試的主體邏輯必須放在一個 for 循環內,循環次數由 b.N 決定:for i := 0; i < b.N; i++go test 命令會自動調整 b.N 的值,反復運行代碼直到獲得穩定可靠的測量結果。

簡單示例

image.png

實踐:比較字符串拼接性能

字符串拼接是一個非常常見的操作,不同的實現方式性能差異巨大。下面我們通過性能測試來實際比較三種方法的優劣:fmt.Sprintf+ 操作符和 strings.Builder

image.png

通過命令行運行測試 使用 go test 命令并附加 -bench 標志。. 作為參數表示運行當前包下所有的性能測試。

go test -bench=.

運行獲取到的結果,具體數值取決于您的機器性能。

根據提供的基準測試結果,以下是各個字符串拼接方法的性能對比分析:

  1. [BenchmarkStringSprintf](file:///Users/jie/Desktop/code/go/onego/xh02/add_test.go#L12-L20)(使用 fmt.Sprintf 拼接)

    • 執行次數:88 次
    • 每次操作耗時:約 13,797,447 ns (13.8 ms)
    • 分析:性能最差,因為 fmt.Sprintf 在每次調用時都需要進行格式解析和內存分配,效率較低。
  2. [BenchmarkStringAdd](file:///Users/jie/Desktop/code/go/onego/xh02/add_test.go#L23-L31)(使用 + 操作符拼接)

    • 執行次數:99 次
    • 每次操作耗時:約 11,765,825 ns (11.8 ms)
    • 分析:比 fmt.Sprintf 快,但由于字符串是不可變類型,每次 + 操作都會創建新字符串并復制內容,性能依然有限。
  3. [BenchmarkStringBuilder](file:///Users/jie/Desktop/code/go/onego/xh02/add_test.go#L34-L43)(使用 strings.Builder 拼接)

    • 執行次數:9418 次
    • 每次操作耗時:約 123,530 ns (0.12 ms)
    • 分析:性能最優。strings.Builder 是專為高效字符串拼接設計的類型,內部使用 []byte 緩沖區,避免了頻繁的內存分配和復制。

總結:

  • strings.Builder 明顯優于其他兩種方式,尤其在大量字符串拼接操作中表現最佳。
  • 避免在循環中使用 fmt.Sprintf+ 進行字符串拼接,除非對性能要求不高。
  • 推薦在性能敏感場景下優先使用 strings.Builder

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

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

相關文章

8. 接口專業測試報告生成pytest-html

pytest-html 終極指南&#xff1a;打造專業級接口測試報告 在接口自動化測試中&#xff0c;清晰的測試報告是質量保障的關鍵。本文將深入解析如何通過pytest-html插件生成專業級測試報告。 一、核心安裝與基礎使用 快速安裝&#xff08;國內鏡像&#xff09; pip install -i …

Day45 Tensorboard使用介紹

目錄 一、tensorboard的發展歷史和原理及基本操作 1.1 發展歷史 1.2 tensorboard的原理 1.3 日志目錄自動管理 1.4 記錄標量數據&#xff08;Scalar&#xff09; 1.5 可視化模型結構&#xff08;Graph&#xff09; 1.6 可視化圖像&#xff08;Image&#xff09; 1.7 記…

用AI給AR加“智慧”:揭秘增強現實智能互動的優化秘密

用AI給AR加“智慧”:揭秘增強現實智能互動的優化秘密 引子:增強現實,到底還能怎么更聰明? 還記得當年Pokmon GO火爆全球的場景嗎?玩家們手機對準街頭,虛擬小精靈活靈活現地跳出來,那就是增強現實(AR)最經典的應用之一。隨著硬件發展和算法進步,AR正逐步從“炫酷玩具…

1 Studying《Computer Vision: Algorithms and Applications 2nd Edition》1-5

目錄 Chapter 1 Introduction 1.1 什么是計算機視覺&#xff1f; 1.2 簡史 1.3 書籍概述 1.4 樣本教學大綱 1.5 符號說明 1.6 其他閱讀材料 Chapter 2 Image formation 2.1 幾何基本元素和變換 2.2 光度圖像形成 2.3 數碼相機 2.4 其他閱讀材料 2.5 練習 Chapter…

Augment插件macOS

macOS蘋果電腦vscode-augment免費額度續杯跑滿 前言 在AI輔助編程日益普及的今天&#xff0c;Augment作為VS Code中的智能代碼助手&#xff0c;為開發者提供了強大的代碼生成和優化功能。然而&#xff0c;免費版本每月300次的使用限制往往讓重度用戶感到困擾。本文將詳細介紹如…

OpenCV CUDA模塊設備層-----創建一個“常量指針訪問器” 的工具函數constantPtr()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 在 CUDA 設備端模擬一個“指向常量值”的虛擬指針訪問器&#xff0c;使得你可以像訪問數組一樣訪問一個固定值。 這在某些核函數中非常有用&…

Python:操作 Excel 刪除工作簿

??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】 【測試經驗】 【人工智能】 【Python】 Python 操作 Excel 系列 讀取單元格數據按行寫入設置行高和列寬自動調整行高和列寬水平…

Python類型注解(Type Hints)的工程實踐指南

一、類型注解的核心價值 代碼可讀性&#xff1a;明確函數輸入輸出類型 靜態檢查&#xff1a;配合mypy提前發現類型錯誤 IDE支持&#xff1a;提升代碼補全和重構能力 文檔替代&#xff1a;類型即文檔的現代編程理念 二、基礎語法規范 def greet(name: str, times: int 1)…

Hadoop RPC 分層設計的哲學:高內聚、低耦合的最佳實踐

Hadoop RPC Hadoop RPC主要分為四個部分&#xff0c;分別是序列化層、函數調用層、網絡傳輸層和服務器端處理框架&#xff0c;實現機制為&#xff1a; 序列化層&#xff1a;主要作用是將結構化對象轉為字節流以便于通過網絡進行傳輸或寫入持久存儲。函數調用層&#xff1a;主…

MybatisPlus-01.MybatisPlus介紹

一.MybatisPlus介紹 MybatisPlus是對Mybatis的增強和升級&#xff0c;但需要注意的是&#xff0c;MybatisPlus并不是取代Mybatis的&#xff0c;而是要做Mybatis最好的合作伙伴。左邊藍色的小鳥就是MybatisPlus的標志。 在MybatisPlus官方頁面上介紹了其特點&#xff0c;首先&am…

人大金倉數據庫jdbc連接jar包kingbase8-8.6.0.jar驅動包最新版下載(不需要積分)

看了網上的很多&#xff0c;都是需要下載積分的 分享一下直接訪問人大金倉官網&#xff0c;下載對應的數據庫jdbc連接jar包kingbase8-8.6.0.jar驅動包&#xff1a; 點擊 服務與支持&#xff0c;然后選擇 下載中心 選擇對應的產品和版本&#xff0c;最后選擇軟件版本 看到有…

cf 禁止http/1.0和http/1.1的訪問 是否會更安全?

使用 Cloudflare&#xff08;CF&#xff09;禁止 HTTP/1.0 和 HTTP/1.1 的訪問&#xff0c;強制客戶端使用 HTTP/2 或更高版本&#xff08;如 HTTP/3&#xff09;&#xff0c;在某些情況下可以提升網站安全性&#xff0c;但也存在權衡和限制。以下是詳細分析&#xff0c;幫你判…

【Docker基礎】Docker容器管理:docker pause詳解

目錄 1 Docker容器管理概述 2 docker pause命令詳解 2.1 命令基本語法 2.2 命令功能解析 2.3 暫停與停止的區別 3 docker pause的工作流程 3.1 工作流程概述 3.2 工作流程詳解 4 docker pause的使用場景 4.1 資源臨時調整 4.2 調試與檢查 4.3 服務維護 4.4 數據備…

Springboot ResponseBodyAdvice 的小妙用

最近公司接觸到了政府項目&#xff0c;在開發完成后&#xff0c;需要對代碼做安全掃描&#xff0c;對系統做安全測試&#xff0c;在安全測試中有一項不合格&#xff0c;就是接口返回錯誤是&#xff0c;錯誤不是瀏覽器級別的&#xff0c;什么意思呢&#xff0c;一般我們都會封裝…

Re:從零開始的文件結構(融合線性表來理解 考研向)

文件管理 & 線性表 文件管理文件的結構無結構文件 有結構文件&#xff08;重點&#xff09;定長與不定長記錄順序文件&#xff08;類線性表&#xff09;它的邏輯結構它的物理結構&#xff08;存儲結構&#xff09;小結 索引順序文件與多級索引順序文件形象化理解&#xff0…

并發基礎7(守護線程)

目錄 1&#xff1a;什么守護線程 2&#xff1a;守護線程使用 3&#xff1a;守護線程案例 1&#xff1a;什么守護線程 守護線程是Java中的一種特殊的線程類型&#xff0c;它為其他線程&#xff08;非守護線程&#xff09;提供后臺支持服務。 在Java多線程編程中&#xff0c…

蜣螂算法+四模型對比!DBO-CNN-BiLSTM-Attention系列四模型多變量時序預測

蜣螂算法四模型對比&#xff01;DBO-CNN-BiLSTM-Attention系列四模型多變量時序預測&#xff08;Matlab完整源碼和數據&#xff09; 目錄 蜣螂算法四模型對比&#xff01;DBO-CNN-BiLSTM-Attention系列四模型多變量時序預測&#xff08;Matlab完整源碼和數據&#xff09;效果一…

服務器的維護技術都有哪些?

服務器的穩定性與可靠性是十分重要的&#xff0c;當服務器出現故障或損壞時&#xff0c;會影響業務的正常運行&#xff0c;還會導致數據丟失給企業帶來巨大的經濟損失&#xff0c;所以大多數的企業通常掌握著有效的服務器維護技術&#xff0c;不僅能夠提高服務器的穩定性&#…

Go 語言并發編程

Go 語言的并發模型是其區別于其他編程語言的重要特性之一&#xff0c;它以簡潔高效的方式解決了現代編程中多核處理器利用和高并發場景的需求。 一、并發與并行&#xff1a;概念與區別 在理解 Go 的并發模型之前&#xff0c;需要明確并發與并行的差異&#xff1a; 并發&…

基于Versoria函數優化協方差更新的改進擴展卡爾曼濾波(MVC-EKF)與經典EKF的對比,附matlab源代碼|訂閱專欄后可查看完整代碼

本代碼實現了基于Versoria函數優化協方差更新的改進擴展卡爾曼濾波(MVC-EKF),并與傳統擴展卡爾曼濾波(EKF)進行對比。代碼通過一維非線性運動模型仿真,展示了MVC-EKF在處理含異常值觀測數據時的魯棒性優勢,適用于目標跟蹤、導航定位等狀態估計場景。訂閱專欄后,可直接查…