1. 程式人生 > >Go 語言單元測試

Go 語言單元測試

go 語言發展非常迅速,大家對go語言程式設計也比較熟悉了,但很多同學對於go語言的測試不太熟悉,最近準備三篇關於Go語言的測試文章來介紹Go語言的測試相關內容。

單元測試框架

go語言提供了編寫go語言的自動化測試框架testing.T,testing.B等,我們通過go test命令就可以來啟動測試。我們編寫測試方法的格式如下:

func TestXxx(*testing.T)

注意這裡的方法名TestXxx中第一個X是大寫,這是一種推薦的規範。測試方法名在實際方法名Xxx前加Test標明這是測試Xxx的方法。

另外,我們推薦將測試檔案取名xxx_test.go這樣的格式,其中xxx

為go原始檔的名稱,方便我們定位某個檔案的測試檔案。go測試檔案和原始檔放在同一個目錄下。該檔案將從常規軟體包構建中排除,但在執行go test命令時將包含該檔案。

單元測試編寫規範

單元測試通常都是通過一組用例資料,作為方法的引數傳入,檢查輸出是否與預期的返回值相同。這種思路也適用於Go語言,只不過在實現形式上推薦採用更為優雅的方式。

假設我們有一個非常簡單的helper.go, 實現兩個整數相加輸出結果的功能,實現程式碼如下:

package helper

func Add(a, b int) int {
    return a + b
}

我們可以寫如下的測試程式碼:

package helper

import (
    "testing"
)

func TestAdd(t *testing.T) {
    var param1 = 1
    var param2 = 1
    var result = 2
    r := Add(param1, param2)
    if r != result {
        if r != result {
            t.Errorf("error: expecte %d, but got %d", result, r)
        }
    }
}

這個程式碼這樣寫並沒有什麼大的問題,如果考慮其擴充套件性,比如增加新的測試場景(程式碼在不斷迭代優化中),程式碼的可讀性就會變得越來越差,如何有效確保擴充套件性的前提下不降低可讀性呢?推薦如下方式:

package helper

import (
    "testing"
)

func TestAdd(t *testing.T) {
    tests := []struct {
        param1 int
        param2 int
        result int
    }{
        {
            param1: 1,
            param2: 1,
            result: 2,
        },
    }

    for _, test := range tests {
        r := Add(test.param1, test.param2)
        if r != test.result {
            t.Errorf("error: expecte %d, but got %d", test.result, r)
        }
    }
}

這種方式下,測試程式碼更加簡潔,在增加新的測試場景的情況下,也不會降低可讀性,這種設計在Kubernetes及阿里Pouch等開源專案中都有此類實踐,大家可以關注。

特殊功能開關

指定執行的方式

可以通過go test -run xxx的形式來指定執行的方法,注意這裡的run引數是正則匹配的,如下所示:

bogon:helper $ go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestExp
--- PASS: TestExp (0.00s)
PASS
ok      demo/helper 0.005s
bogon:helper $ go test -run TestAdd -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      demo/helper 0.005s
bogon:helper $ go test -run TestExp -v
=== RUN   TestExp
--- PASS: TestExp (0.00s)
PASS
ok      demo/helper 0.005s

獲取測試覆蓋率

go 提供了獲取單元測試覆蓋率引數,執行如下命令:

go test -v -coverprofile cover.out
go tool cover -html=cover.out -o cover.html

我們開啟cover.html就可以獲得單元測試覆蓋率資訊,如下所示:

這裡寫圖片描述

限制同時執行的執行緒數

go語言有一個GOMAXPROCS變數,可以指定執行Go程式碼的作業系統執行緒數。如果執行時不加該引數,則就是當前所設定的GOMAXPROCS值。

bogon:helper $ go test -cpu 1
PASS
ok      demo/helper 0.005s

總結

Go語言是一個嚴禁且高效的開發語言,在單元測試方面,提供了很多好的工程實踐,這些思想可以在其他語言中採用,這一篇是一個開始,後續會介紹Go語言測試的Benchmark部分,主要是針對性能相關部分的內容。