Go-單元測試詳解與代碼

目錄golang

概述運維

Go的單元測試ide

基礎知識函數

快速入門性能

進階單元測試

單個文件的測試測試

單個函數的測試ui

單元測試覆蓋率日誌

參考code


概述

常言道,不會測試的程序猿不是好的產品經理!!!如今愈來愈多測試和運維的工做也須要研發來作了,本篇文章就來說講Go的單元測試。

單元測試(unit testing),是指對軟件中的最小可測試單元進行檢查和驗證。簡單說,就是將測試用例的運行結果與預期結果進行比較。

Go的單元測試

基礎知識

Go有testing測試包,配合go test命令可以進行單元測試。

  1. 測試文件以_test.go結尾
  2. 在包目錄內,全部以_test.go爲後綴名的源代碼文件都是go test測試的一部分,不會被go build編譯到最終的可執行文件中。
  3. _test.go文件包含TestXxx函數
  4. 形參類型必須爲*test.T
  5. PASS表示測試用例運行成功,FAIL表示失敗

我的經常使用Fatalf,這裏就來具體說一下,其餘函數見參考的連接。

func (c *T) Logf(format string, args ...interface{})

Log 使用與 Printf 相同的格式化語法對它的參數進行格式化,而後將格式化後的文本記錄到錯誤日誌裏面。 若是輸入的格式化文本最末尾沒有出現新行,那麼將一個新行添加到格式化後的文本末尾。

1)對於測試來講,Logf 產生的格式化文本只會在測試失敗或者設置了 -test.v 標誌的狀況下被打印出來;

2)對於基準測試來講,爲了不 -test.v 標誌的值對測試的性能產生影響,Logf 產生的格式化文本總會被打印出來

func (c *T) FailNow()

將當前測試標識爲失敗並中止執行該測試,在此以後,測試過程將在下一個測試或者下一個基準測試中繼續。

FailNow 必須在運行測試函數或者基準測試函數的 goroutine 中調用,而不能在測試期間建立的 goroutine 中調用。調用 FailNow 不會致使其餘 goroutine 中止。

func (c *T) Fatalf(format string, args ...interface{})

調用 Fatalf 至關於在調用 Logf 以後調用 FailNow 。 

快速入門

項目結構

learnGo
└── main
    ├── compute.go
    └── compute_test.go

compute.go

package main

import "errors"

func div(a,b int) (int,error) {
	if b != 0{
		return a/b,nil
	} else{
		return 0,errors.New("b is 0")
	}
}

compute_test.go

package main

import "testing"

func TestDiv(t *testing.T)  {
	res,_ := div(4,2)
	want := 2
	if res != want{
		t.Fatalf("期待:%d ,實際結果:%d",want,res)
	}
}

main目錄下運行

go test -v

結果以下:

=== RUN   TestDiv
--- PASS: TestDiv (0.00s)
PASS
ok      learnGo/main    0.457s

以上咱們就針對main包的compute.go文件進行了單元測試。

進階

查看更多的選項,可以使用

go help test

go help testflag

單個文件的測試

咱們在main包中再添加str.go及str_test.go

str.go

package main

func getSub(str string,start,end int) string {
	// 左閉右閉
	if 0<=start&&start<end&&end<=len(str){
		return str[start:end]
	}else{
		return ""
	}
}

str_test.go

package main

import "testing"

func TestGetSub(t *testing.T)  {
	astr := "lady_killer9"
	// 包含開頭
	res1 := getSub(astr,0,4)
	want1 := "lady"
	// 包含結尾
	res2 := getSub(astr,4,len(astr))
	want2 := "_killer9"
	// 範圍錯誤
	res3 := getSub(astr,1,len(astr)+1)
	want3 := ""
	if res1 != want1{
		t.Errorf("指望:%s,實際結果:%s",want1,res1)
	}
	if res2 != want2{
		t.Errorf("指望:%s,實際結果:%s",want2,res2)
	}
	if res3 != want3{
		t.Errorf("指望:%s,實際結果:%s",want3,res3)
	}
}

運行 go test -v,獲得結果以下

=== RUN   TestDiv
--- PASS: TestDiv (0.00s)
=== RUN   TestGetSub
--- PASS: TestGetSub (0.00s)
PASS
ok      learnGo/main    0.446s

go test會運行全部的單元測試,有時候咱們只想測試某個文件

若是隻是運行一個測試文件,可添加參數

go test -v 測試文件 源文件

運行go test -v str_test.go str.go, 結果以下:

=== RUN   TestGetSub
--- PASS: TestGetSub (0.00s)
PASS
ok      command-line-arguments  0.619s

單個函數的測試

咱們在compute.go中添加

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

在compute_test.go中添加

func TestAdd(t *testing.T)  {
	a,b:=3,4
	res := add(a,b)
	want := 7
	if res != want{
		t.Fatalf("期待:%d,實際結果:%d",want,res)
	}
}

因爲對div函數未作改動,只想測試add函數,可使用參數-test.run指定測試函數

go test -v -test.run 測試函數

運行 go test -v -test.run TestAdd 結果以下:

=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      learnGo/main    0.836s

單元測試覆蓋率

測試應該全面,達到100%。

可使用-cover參數

go test -cover

結果以下:

PASS
coverage: 85.7% of statements
ok      learnGo/main    0.505s

能夠看到,測試的並不全面,指定測試文件來查看。

go test -cover compute_test.go compute.go

ok      command-line-arguments  0.314s  coverage: 75.0% of statements

觀察發現,咱們缺乏了b爲0的分支,修改TestDiv函數爲

func TestDiv(t *testing.T)  {
	res,_ := div(4,2)
	want := 2
	if res != want{
		t.Fatalf("期待:%d,實際結果:%d",want,res)
	}
	res,_ = div(3,0)
	want = 0
	if res != want{
		t.Fatalf("期待:%d,實際結果:%d",want,res)
	}
}

測試後再看覆蓋率,結果以下

PASS
coverage: 100.0% of statements
ok      learnGo/main    0.306s

做爲開發,基本的單元測試就能夠了,還能夠去了解基準測試、性能測試、壓力測試、黑盒測試等。

參考

Go標準庫-testing

相關文章
相關標籤/搜索