跳至主要内容

[Go] 單元測試與性能測試

本文會介紹 Go 的單元測試方式,會使用預設的套件來進行單元測試跟性能測試

單元測試

在寫單元測試時,有一些知識需要了解 :

  • 單元測試是測試最小的程式碼單位,通常是一個 function 或者一個 method
  • 一個測試案例僅測試一個功能,不同 test case 之間不應該有相依性
  • 不與外部系統互動,不會有 I/O、網路請求與資料庫操作等等

接下來會使用 Go 的內建套件 testing 搭配 mockgen 來撰寫單元測試,安裝前需要確保 GOBIN 在 PATH 中

go get github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen

在下面這個範例中,我們有一個 Calculator 的 interface,裡面有一個 Add 的 method,接著有一個 ComputeSum 的 function 會呼叫 CalculatorAdd method

go mod init unittest
calculator.go
package calculator

type Calculator interface {
Add(a, b int) int
}

func ComputeSum(calc Calculator, a, b int) int {
return calc.Add(a, b)
}

首先我們需要 mock Calculator 的 interface,方便做出一些假的結果來避免去與外部作互動

接著我們可以使用 mockgen 來產生 mock 的程式碼

  • -source : 要 mock 的檔案
  • -destination : 產生的 mock 檔案
  • -package : mock 檔案的 package 名稱,沒寫的話預設是 mock_<source_package_name>
mockgen -source calculator.go -destination mocks/mock_calculator.go -package mocks

最後就可以來寫單元測試了,我們可以使用 testing 套件來撰寫單元測試,記得檔案名稱要以 _test.go 結尾,測試的 function 名稱要以 Test 開頭

calculator_test.go
package calculator_test

import (
"testing"

calculator "unittest"

"unittest/mocks"

"github.com/golang/mock/gomock"
)

func TestComputeSum(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockCalc := mocks.NewMockCalculator(ctrl)

a, b := 1, 2
mockCalc.EXPECT().Add(a, b).Return(a + b)

result := calculator.ComputeSum(mockCalc, a, b)
if result != 3 {
t.Errorf("ComputeSum(%d, %d) = %d; want 3", a, b, result)
}
}

接著介紹一些單元測試常用的指令 :

  • go test : 執行所有的單元測試

  • go test -v : 執行所有的單元測試並且顯示詳細的結果

  • go test -run <test_function_name> : 執行特定的單元測試,可以使用正規表達式也可以只寫部分名稱

  • go test -run <file_name> : 執行特定的檔案的單元測試

  • go test -cover : 顯示測試覆蓋率

  • go test -coverprofile coverage.out : 產生測試覆蓋率的檔案

  • go tool cover -html=coverage.out : 顯示測試覆蓋率的 HTML

  • start coverage.html : 用瀏覽器開啟測試覆蓋率的 HTML (適用於 Windows,Mac 可以使用 open coverage.html)