<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 3122字,需瀏覽 7分鐘

           ·

          2021-12-31 21:24

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


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


          所有的代碼都需要寫測(cè)試用例。這不僅僅是對(duì)自己的代碼負(fù)責(zé),也是對(duì)別人的負(fù)責(zé)。
          最近工作中使用glog這個(gè)庫(kù),因?yàn)樗鼘?duì)外提供的方法都很簡(jiǎn)單,想封裝處理一下。但卻遇到了點(diǎn)麻煩:這個(gè)包需要在命令行傳遞log_dir參數(shù),來(lái)指定日志文件的路徑。

          所以,正常運(yùn)行的話,首先需要編譯可執(zhí)行文件,然后命令行指定參數(shù)執(zhí)行。如下示例:
          go?build?main.go
          ./main?-log_dir="/data"????//當(dāng)前目錄作為日志輸出目錄

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

          Test

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

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

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

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

          func?TestGetRootLogger(t?*testing.T)?{
          ?writeLog("測(cè)試")
          }

          func?TestGetRootLogger2(t?*testing.T)?{
          ?writeLog("測(cè)試?2")
          }

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

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

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

          option

          -timeout

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

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

          使用map的測(cè)試

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

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

          func?TestSum(t?*testing.T)?{
          ?t.Run("A",?testSumFunc([]int{1,?2,?3},?7))
          ?t.Run("B",?testSumFunc([]int{2,?3,?4},?8))
          }

          func?Sum(numbers?[]int)?int?{
          ?total?:=?0
          ?for?_,?v?:=?range?numbers?{
          ??total?+=?v
          ?}

          ?return?total
          }

          func?testSumFunc(numbers?[]int,?expected?int)?func(t?*testing.T)?{
          ?return?func(t?*testing.T)?{
          ??actual?:=?Sum(numbers)
          ??if?actual?!=?expected?{
          ???t.Error(fmt.Sprintf("Expected?the?sum?of?%v?to?be?%d?but?instead?got?%d!",?numbers,?expected,?actual))
          ??}
          ?}
          }

          Main

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

          func?TestMain(m?*testing.M)?{
          ????//準(zhǔn)備工作
          ?fmt.Println("start?prepare")

          ?flag.Parse()
          ?exitCode?:=?m.Run()
          ????
          ????//清理工作
          ?fmt.Println("prepare?to?clean")
          ?
          ?os.Exit(exitCode)
          }

          性能測(cè)試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.

          性能測(cè)試涉及如下方面:

          1. CPU ProfilingCPU分析,按照一定的頻率采集所監(jiān)聽(tīng)的應(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)告互斥鎖的競(jìng)爭(zhēng)情況

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

          _?"net/http/pprof"

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

          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文件。如下所示:

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

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

          ##?通過(guò)在瀏覽器中?localhost:1313?可以在?web?端查看
          ##?
          pprof?-http=:1313?cpu.prof

          ##?或直接在終端查看
          go?tool?pprof?cpu.prof
          $?web?|?top

          Benchmark測(cè)試

          基本用法:

          func?BenchmarkBadgeRelationMapper_GetCountByUid(b?*testing.B)?{

          ?count?:=?0
          ?for?i?:=?0;?i???count++
          ?}
          ?fmt.Println("total:",?count)
          }

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

          total:?1
          total:?100
          total:?10000
          total:?1000000
          total:?100000000
          total:?1000000000
          1000000000??????????0.598?ns/op

          并發(fā)用法:

          func?BenchmarkBadgeRelationMapper_GetCountByUid(b?*testing.B)?{

          ?count?:=?0
          ?b.RunParallel(func(pb?*testing.PB)?{
          ??for?pb.Next()?{
          ???count++
          ??}
          ?})

          ?fmt.Println("total:",?count)
          }

          輸出的結(jié)果:

          total:?1
          total:?100
          total:?6336
          total:?306207
          total:?34221963
          total:?129821900
          378966799??????????2.94?ns/op

          在并行用法中,b.NRunParallel接管。

          簡(jiǎn)單分析一下源碼

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

          //?Next?reports?whether?there?are?more?iterations?to?execute.
          func?(pb?*PB)?Next()?bool?{
          ?if?pb.cache?==?0?{
          ??n?:=?atomic.AddUint64(pb.globalN,?pb.grain)
          ??if?n?<=?pb.bN?{
          ???pb.cache?=?pb.grain
          ??}?else?if?n????pb.cache?=?pb.bN?+?pb.grain?-?n
          ??}?else?{
          ???return?false
          ??}
          ?}
          ?pb.cache--
          ?return?true
          }

          regular expression

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

          //?-bench?takes?a?regular?expression?that?matches?the?names?of?the?benchmarks?you?want?to?run
          go?test?-bench=.?./examples/fib/

          //?-run?flag?with?a?regex?that?matches?nothing
          go?test?-run=^$

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

          go?test?-bench=.

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

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

          還有一個(gè)參數(shù):benchmem??梢蕴峁┟看尾僮鞣峙鋬?nèi)存的次數(shù),以及每次操作分配的字節(jié)數(shù)。

          go?test?-bench=Fib40?-benchtime=20s

          Run Example

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

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

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

          ##?對(duì)函數(shù)?GetGiftReceiveList?進(jìn)行?Benchmark?測(cè)試?因?yàn)橹幌雺簻y(cè)?GetGiftReceiveList?這個(gè)函數(shù)
          ##?所以指定了?run?參數(shù)
          go?test?-bench?.?-run=GetGiftReceiveList?-benchmem?-cpuprofile?prof.cpu

          #
          #?其中?present.test?是壓測(cè)的二進(jìn)制文件,prof.cpu?也是生產(chǎn)的文件
          ##?(pprof)?top10
          ##?(pprof)?list?Marshal?單獨(dú)查看這個(gè)函數(shù)的耗時(shí),這里應(yīng)該是正則匹配的
          go?tool?pprof?present.test?prof.cpu

          #
          #?查看內(nèi)存使用情況
          go?test?-bench?.?-benchmem?-memprofile?prof.mem
          go?tool?pprof?--alloc_objects??present.test?prof.mem

          覆蓋率

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

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

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

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

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

          火焰圖

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

          ##?tool1
          git?clone?https://github.com/brendangregg/FlameGraph.git
          cp?flamegraph.pl?/usr/local/bin
          flamegraph.pl?-h

          go?get?-v?github.com/uber/go-torch
          go-torch?-h

          文章轉(zhuǎn)載:Go開(kāi)發(fā)大全

          (版權(quán)歸原作者所有,侵刪)


          點(diǎn)擊下方“閱讀原文”查看更多

          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产在线播放日本 | 久久色亚洲 | 一区二区三区四区五区六区在线 | 校园激情一区 | 日本A一级片|