自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go test基礎(chǔ)用法大全

開發(fā) 后端
go 語言的 test 命令有很多參數(shù),怎么利用 test 命令和它提供的參數(shù),又能做到什么?本文做了詳細(xì)解讀。

[[442478]]

 go 語言的 test 命令有很多參數(shù),怎么利用 test 命令和它提供的參數(shù),又能做到什么?本文做了詳細(xì)解讀。

當(dāng)直接使用IDE進(jìn)行單元測試時(shí),有沒有好奇它時(shí)如何實(shí)現(xiàn)的?比如GoLand寫的測試用例。

所有的代碼都需要寫測試用例。這不僅僅是對自己的代碼負(fù)責(zé),也是對別人的負(fù)責(zé)。

最近工作中使用glog這個(gè)庫,因?yàn)樗鼘ν馓峁┑姆椒ǘ己芎唵危敕庋b處理一下。但卻遇到了點(diǎn)麻煩:這個(gè)包需要在命令行傳遞log_dir參數(shù),來指定日志文件的路徑。

所以,正常運(yùn)行的話,首先需要編譯可執(zhí)行文件,然后命令行指定參數(shù)執(zhí)行。如下示例: 

  1. go build main.go  
  2. ./main -log_dir="/data"    //當(dāng)前目錄作為日志輸出目錄 

但在go test的時(shí)候,如何指定這個(gè)參數(shù)了?

Test

調(diào)查發(fā)現(xiàn),發(fā)現(xiàn)go test也可以生成可執(zhí)行文件。需要使用-c來指定。示例如下: 

  1. go test -c param_test_dir   //最后一個(gè)參數(shù)是待測試的目錄 

執(zhí)行后就會(huì)發(fā)現(xiàn):這樣的做法,會(huì)運(yùn)行所有的Test用例。如何僅僅執(zhí)行某一個(gè)測試用例了(編譯器到底是如何做到的?)。

這里有另一個(gè)屬性-run,用來指定執(zhí)行的測試用例的匹配模式。舉個(gè)例子: 

  1. func TestGetRootLogger(t *testing.T) {  
  2.  writeLog("測試")  
  3.  
  4. func TestGetRootLogger2(t *testing.T) {  
  5.  writeLog("測試 2")  

當(dāng)我在命令行明確匹配執(zhí)行Logger2,運(yùn)行的時(shí)候確實(shí)僅僅執(zhí)行該測試用例 

  1. go test -v -run Logger2 ./util/     //-v 表示 verbose,輸出相信信息 

但是,我發(fā)現(xiàn),在指定了c參數(shù)之后,run參數(shù)無法生效!這樣的話,還真是沒有好的辦法來處理這種情況。

option

  1. -timeout 

默認(rèn)go test運(yùn)行超過10m會(huì)發(fā)生panic。如果需要運(yùn)行更長的時(shí)間,需要明確指定。將timeout指定為 0,用于忽略時(shí)間限制。 

  1. nohup go test -v -timeout 0 -run TestGetRange . > log.txt 

使用map的測試

可以結(jié)合使用閉包,設(shè)置期望值,來寫測試用例。Run函數(shù)內(nèi)部是阻塞的,所以TestSum方法依次執(zhí)行測試。

同時(shí)testSumFunc返回了test方法使用了閉包的特性,對返回函數(shù)內(nèi)部的值是無法確定的。 

  1. func TestSum(t *testing.T) {  
  2.  t.Run("A", testSumFunc([]int{1, 2, 3}, 7))  
  3.  t.Run("B", testSumFunc([]int{2, 3, 4}, 8))  
  4.  
  5. func Sum(numbers []int) int {  
  6.  total :0  
  7.  for _, v :range numbers {  
  8.   total += v  
  9.  }  
  10.  return total  
  11.  
  12. func testSumFunc(numbers []int, expected int) func(t *testing.T) {  
  13.  return func(t *testing.T) {  
  14.   actual :Sum(numbers)  
  15.   if actual != expected {  
  16.    t.Error(fmt.Sprintf("Expected the sum of %v to be %d but instead got %d!", numbers, expected, actual))  
  17.   }  
  18.  } 

Main

非常簡單,看如下示例。這樣在執(zhí)行任何test case時(shí)都首先執(zhí)行準(zhǔn)備,在測試用例執(zhí)行完畢后,會(huì)運(yùn)行清理工作。需要特別說明的是:flag.Parse()以及os.Exit(m.Run())是不可缺少的兩步。 

  1. func TestMain(m *testing.M) {  
  2.     //準(zhǔn)備工作  
  3.  fmt.Println("start prepare")  
  4.  flag.Parse()  
  5.  exitCode :m.Run()  
  6.         //清理工作  
  7.  fmt.Println("prepare to clean")  
  8.   os.Exit(exitCode)  

性能測試pprof

定位服務(wù)是否存在資源泄漏或者濫用API的行為,光靠review代碼是不行的,最好能借助工具。

Profile

引用 godoc for pprof 描述:

A Profile is a collection of stack traces showing the call sequences that led to instances of a particular event, such as allocation. Packages can create and maintain their own profiles; the most common use is for tracking resources that must be explicitly closed, such as files or network connections.

性能測試涉及如下方面:

  1.  CPU Profiling:CPU分析,按照一定的頻率采集所監(jiān)聽的應(yīng)用程序CPU(含寄存器)的使用情況,可確定應(yīng)用程序在主動(dòng)消耗CPU 周期時(shí)花費(fèi)時(shí)間的位置
  2.  Memory Profiling:內(nèi)存分析,在應(yīng)用程序進(jìn)行堆分配時(shí)記錄堆棧跟蹤,用于監(jiān)視當(dāng)前和歷史內(nèi)存使用情況,以及檢查內(nèi)存泄漏
  3.  Block Profiling:阻塞分析,記錄 goroutine 阻塞等待同步(包括定時(shí)器通道)的位置
  4.  Mutex Profiling:互斥鎖分析,報(bào)告互斥鎖的競爭情況

在程序中引入如下包,便可以通過 web 方式查看性能情況,訪問的路徑為:/debug/pprof/,該路徑下會(huì)顯示多個(gè)查看項(xiàng)。該路徑下還有其他子頁面。 

  1. _ "net/http/pprof" 

關(guān)于/debug/pprof/下的子頁面:

  1.  $HOST/debug/pprof/profile
  2.  $HOST/debug/pprof/block
  3.  $HOST/debug/pprof/goroutine
  4.  $HOST/debug/pprof/heap
  5.  $HOST/debug/pprof/mutex
  6.  $HOST/debug/pprof/threadcreate

在終端查看性能

只要服務(wù)器在啟動(dòng)時(shí),引入pprof包,便可在終端獲取profile文件。如下所示: 

  1. pprof -seconds=10 http://192.168.77.77:3900/debug/pprof/profile 

如果獲取到cpu.prof文件,可以通過如下命令可視化查看運(yùn)行結(jié)果,這是另一種格式的火焰圖,也是挺帥的: 

  1. ## 通過在瀏覽器中 localhost:1313 可以在 web 端查看  
  2. ##   
  3. pprof -http=:1313 cpu.prof  
  4. ## 或直接在終端查看  
  5. go tool pprof cpu.prof  
  6. $ web | top 

Benchmark測試

基本用法: 

  1. func BenchmarkBadgeRelationMapper_GetCountByUid(b *testing.B) {  
  2.  count :0  
  3.  for i :0; i < b.N; i++ {  
  4.   count++  
  5.  }  
  6.  fmt.Println("total:", count)  

bench測試輸出結(jié)果,函數(shù)體被重復(fù)執(zhí)行了 6 次,并對b.N的值做了調(diào)整: 

  1. total: 1  
  2. total: 100  
  3. total: 10000  
  4. total: 1000000  
  5. total: 100000000  
  6. total: 1000000000  
  7. 1000000000          0.598 ns/op 

并發(fā)用法: 

  1. func BenchmarkBadgeRelationMapper_GetCountByUid(b *testing.B) {  
  2.  count :0  
  3.  b.RunParallel(func(pb *testing.PB) {  
  4.   for pb.Next() {  
  5.    count++  
  6.   }  
  7.  })  
  8.  fmt.Println("total:", count)  

輸出的結(jié)果: 

  1. total: 1  
  2. total: 100  
  3. total: 6336  
  4. total: 306207  
  5. total: 34221963  
  6. total: 129821900  
  7. 378966799          2.94 ns/op 

在并行用法中,b.N被RunParallel接管。

簡單分析一下源碼

核心思路在于Next方法,通過atomic.AddUint64并發(fā)安全的操作pb.globalN,pb.cache用來存儲(chǔ)該goroutine執(zhí)行的次數(shù)。當(dāng)某個(gè)goroutine計(jì)算到pb.bN<=n<=pb.bN+pb.grain時(shí),雖然程序迭代次數(shù)已經(jīng)完全超過b.N,但還是會(huì)讓它繼續(xù)執(zhí)行。 

  1. // Next reports whether there are more iterations to execute.  
  2. func (pb *PB) Next() bool {  
  3.  if pb.cache == 0 {  
  4.   n :atomic.AddUint64(pb.globalN, pb.grain)  
  5.   if n <= pb.bN {  
  6.    pbpb.cache = pb.grain  
  7.   } else if n < pb.bN+pb.grain {  
  8.    pbpb.cache = pb.bN + pb.grain - n  
  9.   } else {  
  10.    return false  
  11.   }  
  12.  }  
  13.  pb.cache--  
  14.  return true  

regular expression

先列舉參考的example。在我們要運(yùn)行特定case時(shí),可以通過指定正則表達(dá)式來實(shí)現(xiàn): 

  1. // -bench takes a regular expression that matches the names of the benchmarks you want to run  
  2. go test -bench=. ./examples/fib/  
  3. // -run flag with a regex that matches nothing  
  4. go test -run=^$ 

關(guān)于如何運(yùn)行Benchmark測試,默認(rèn)執(zhí)行g(shù)o test并不會(huì)執(zhí)行Benchmark,需要在命令行明確加上-bench=標(biāo)記,它接受一個(gè)表達(dá)式作為參數(shù),匹配基準(zhǔn)測試的函數(shù),. 表示運(yùn)行所有基準(zhǔn)測試。 

  1. go test -bench=.  
  2. // 明確指定要運(yùn)行哪個(gè)測試,傳遞一個(gè)正則表達(dá)式給 run 屬性,XXX=BenchmarkReceiveGift_GetGiftReceiveList  
  3. go test -run=XXX -bench=. 

默認(rèn)情況下,benchmark最小運(yùn)行時(shí)長為1s。如果benchmark函數(shù)執(zhí)行返回,但1s的時(shí)間還沒有結(jié)束,b.N會(huì)根據(jù)某種機(jī)制依次遞增??梢酝ㄟ^參數(shù)-benchtime=20s來改變這種行為。

還有一個(gè)參數(shù):benchmem。可以提供每次操作分配內(nèi)存的次數(shù),以及每次操作分配的字節(jié)數(shù)。

  1. go test -bench=Fib40 -benchtime=20s 

Run Example

獲取線上的pprof數(shù)據(jù)到本地,這里是另一個(gè)工具: 

  1. go-torch -u http://192.168.77.77:3900/debug/pprof/profile -t 10 

在Go 代碼調(diào)優(yōu)利器-火焰圖這篇文章中,對例子介紹的挺精彩的。 

  1. ## 對函數(shù) GetGiftReceiveList 進(jìn)行 Benchmark 測試 因?yàn)橹幌雺簻y GetGiftReceiveList 這個(gè)函數(shù)  
  2. ## 所以指定了 run 參數(shù)  
  3. go test -bench . -run=GetGiftReceiveList -benchmem -cpuprofile prof.cpu  
  4. ## 其中 present.test 是壓測的二進(jìn)制文件,prof.cpu 也是生產(chǎn)的文件  
  5. ## (pprof) top10  
  6. ## (pprof) list Marshal 單獨(dú)查看這個(gè)函數(shù)的耗時(shí),這里應(yīng)該是正則匹配的  
  7. go tool pprof present.test prof.cpu  
  8. ## 查看內(nèi)存使用情況  
  9. go test -bench . -benchmem -memprofile prof.mem  
  10. go tool pprof --alloc_objects  present.test prof.mem 

覆蓋率

跟執(zhí)行g(shù)o test不同的是,需要多加一個(gè)參數(shù)-coverprofile, 所以完整的命令: 

  1. go test -v -coverprofile=c.out 

生成報(bào)告有 go 為我們提供的工具,使用 

  1. go tool cover -html=c.out -o=tag.html 

即可生成一個(gè)名字為 tag.html 的 HTML 格式的測試覆蓋率報(bào)告,這里有詳細(xì)的信息告訴我們哪一行代碼測試到了,哪一行代碼沒有測試到。

火焰圖

學(xué)習(xí)了解火焰圖,分析函數(shù)調(diào)用棧的信息。主要是相關(guān)的工具: 

  1. ## tool1  
  2. git clone https://github.com/brendangregg/FlameGraph.git  
  3. cp flamegraph.pl /usr/local/bin  
  4. flamegraph.pl -h  
  5. go get -v github.com/uber/go-torch  
  6. go-torch -h  

 

責(zé)任編輯:龐桂玉 來源: 馬哥Linux運(yùn)維
相關(guān)推薦

2010-07-19 15:01:26

Perl數(shù)學(xué)函數(shù)

2010-07-20 12:52:26

Perl特殊變量

2010-07-19 11:00:24

Perl操作符

2013-05-22 16:34:34

iOS開發(fā)String用法iOS筆記

2018-12-29 15:50:06

Python基礎(chǔ)知識(shí)編程語言

2010-07-16 11:22:31

Perl

2010-07-19 13:06:13

Perl二維數(shù)組

2021-10-12 13:35:30

C++Set紅黑樹

2011-01-17 10:57:55

思科認(rèn)證

2023-12-30 10:22:57

Go語言函數(shù)開發(fā)

2020-12-02 09:10:22

Go結(jié)構(gòu)數(shù)據(jù)類型

2023-08-07 14:28:07

SpringBoot工具

2010-07-23 13:16:07

Perl

2021-09-16 10:05:09

鴻蒙HarmonyOS應(yīng)用

2010-08-31 10:57:44

clipCSS

2020-10-21 12:45:12

Redis數(shù)據(jù)結(jié)構(gòu)

2009-05-26 12:13:24

test

2009-05-26 12:14:34

test

2009-05-26 12:13:24

test

2022-08-31 07:24:56

Docker日志命令
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號