欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Go?語言如何通過測試保證質(zhì)量

 更新時間:2022年08月24日 11:00:48   作者:lianglianglee  
這篇文章主要為大家介紹了Go?語言如何通過測試保證質(zhì)量詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

本節(jié)帶你學(xué)習(xí)本專欄的第四模塊:工程管理?,F(xiàn)在項目的開發(fā)都不是一個人可以完成的,需要多人進(jìn)行協(xié)作,那么在多人協(xié)作中如何保證代碼的質(zhì)量,你寫的代碼如何被其他人使用,如何優(yōu)化代碼的性能等, 就是第四模塊的內(nèi)容。

這一講首先來學(xué)習(xí) Go 語言的單元測試和基準(zhǔn)測試。

單元測試

在開發(fā)完一個功能后,你可能會直接把代碼合并到代碼庫,用于上線或供其他人使用。但這樣是不對的,因為你還沒有對所寫的代碼進(jìn)行測試。沒有經(jīng)過測試的代碼邏輯可能會存在問題:如果強行合并到代碼庫,可能影響其他人的開發(fā);如果強行上線,可能導(dǎo)致線上 Bug、影響用戶使用。

什么是單元測試

顧名思義,單元測試強調(diào)的是對單元進(jìn)行測試。在開發(fā)中,一個單元可以是一個函數(shù)、一個模塊等。一般情況下,你要測試的單元應(yīng)該是一個完整的最小單元,比如 Go 語言的函數(shù)。這樣的話,當(dāng)每個最小單元都被驗證通過,那么整個模塊、甚至整個程序就都可以被驗證通過。

單元測試由開發(fā)者自己編寫,也就是誰改動了代碼,誰就要編寫相應(yīng)的單元測試代碼以驗證本次改動的正確性。

Go 語言的單元測試

雖然每種編程語言里單元測試的概念是一樣的,但它們對單元測試的設(shè)計不一樣。Go 語言也有自己的單元測試規(guī)范,下面我會通過一個完整的示例為你講解,這個例子就是經(jīng)典的斐波那契數(shù)列。

斐波那契數(shù)列是一個經(jīng)典的黃金分隔數(shù)列:它的第 0 項是 0;第 1 項是 1;從第 2 項開始,每一項都等于前兩項之和。所以它的數(shù)列是:0、1、1、2、3、5、8、13、21……

說明:為了便于總結(jié)后面的函數(shù)方程式,我這里特意寫的從第 0 項開始,其實現(xiàn)實中沒有第 0 項。

根據(jù)以上規(guī)律,可以總結(jié)出它的函數(shù)方程式。

F(0)=0

F(1)=1

F(n)=F(n - 1)+F(n - 2)

有了函數(shù)方程式,再編寫一個 Go 語言函數(shù)來計算斐波那契數(shù)列就比較簡單了,代碼如下:

ch18/main.go

func Fibonacci(n int) int {
   if n < 0 {
      return 0
   }
   if n == 0 {
      return 0
   }
   if n == 1 {
      return 1
   }
   return Fibonacci(n-1) + Fibonacci(n-2)
}

也就是通過遞歸的方式實現(xiàn)了斐波那契數(shù)列的計算。

Fibonacci 函數(shù)已經(jīng)編寫好了,可以供其他開發(fā)者使用,不過在使用之前,需要先對它進(jìn)行單元測試。你需要新建一個 go 文件用于存放單元測試代碼。剛剛編寫的 Fibonacci 函數(shù)在ch18/main.go文件中,那么對 Fibonacci 函數(shù)進(jìn)行單元測試的代碼需要放在ch18/main_test.go中*,*測試代碼如下:

ch18/main_test.go

func TestFibonacci(t *testing.T) {
   //預(yù)先定義的一組斐波那契數(shù)列作為測試用例
   fsMap := map[int]int{}
   fsMap[0] = 0
   fsMap[1] = 1
   fsMap[2] = 1
   fsMap[3] = 2
   fsMap[4] = 3
   fsMap[5] = 5
   fsMap[6] = 8
   fsMap[7] = 13
   fsMap[8] = 21
   fsMap[9] = 34
   for k, v := range fsMap {
      fib := Fibonacci(k)
      if v == fib {
         t.Logf("結(jié)果正確:n為%d,值為%d", k, fib)
      } else {
         t.Errorf("結(jié)果錯誤:期望%d,但是計算的值是%d", v, fib)
      }
   }
}

在這個單元測試中,我通過 map 預(yù)定義了一組測試用例,然后通過 Fibonacci 函數(shù)計算結(jié)果。同預(yù)定義的結(jié)果進(jìn)行比較,如果相等,則說明 Fibonacci 函數(shù)計算正確,不相等則說明計算錯誤。

然后即可運行如下命令,進(jìn)行單元測試:

? go test -v ./ch18

這行命令會運行 ch18 目錄下的所有單元測試,因為我只寫了一個單元測試,所以可以看到結(jié)果如下所示:

? go test -v ./ch18 
=== RUN   TestFibonacci
    main_test.go:21: 結(jié)果正確:n為0,值為0
    main_test.go:21: 結(jié)果正確:n為1,值為1
    main_test.go:21: 結(jié)果正確:n為6,值為8
    main_test.go:21: 結(jié)果正確:n為8,值為21
    main_test.go:21: 結(jié)果正確:n為9,值為34
    main_test.go:21: 結(jié)果正確:n為2,值為1
    main_test.go:21: 結(jié)果正確:n為3,值為2
    main_test.go:21: 結(jié)果正確:n為4,值為3
    main_test.go:21: 結(jié)果正確:n為5,值為5
    main_test.go:21: 結(jié)果正確:n為7,值為13
--- PASS: TestFibonacci (0.00s)
PASS
ok      gotour/ch18     (cached)

在打印的測試結(jié)果中,你可以看到 PASS 標(biāo)記,說明單元測試通過,而且還可以看到我在單元測試中寫的日志。

這就是一個完整的 Go 語言單元測試用例,它是在 Go 語言提供的測試框架下完成的。Go 語言測試框架可以讓我們很容易地進(jìn)行單元測試,但是需要遵循五點規(guī)則。

  • 含有單元測試代碼的 go 文件必須以 _test.go 結(jié)尾,Go 語言測試工具只認(rèn)符合這個規(guī)則的文件。
  • 單元測試文件名 _test.go 前面的部分最好是被測試的函數(shù)所在的 go 文件的文件名,比如以上示例中單元測試文件叫 main_test.go,因為測試的 Fibonacci 函數(shù)在 main.go 文件里。
  • 單元測試的函數(shù)名必須以 Test 開頭,是可導(dǎo)出的、公開的函數(shù)。
  • 測試函數(shù)的簽名必須接收一個指向 testing.T 類型的指針,并且不能返回任何值。
  • 函數(shù)名最好是 Test + 要測試的函數(shù)名,比如例子中是 TestFibonacci,表示測試的是 Fibonacci 這個函數(shù)。

遵循以上規(guī)則,你就可以很容易地編寫單元測試了。單元測試的重點在于熟悉業(yè)務(wù)代碼的邏輯、場景等,以便盡可能地全面測試,保障代碼質(zhì)量。

單元測試覆蓋率

以上示例中的 Fibonacci 函數(shù)是否被全面地測試了呢?這就需要用單元測試覆蓋率進(jìn)行檢測了。

Go 語言提供了非常方便的命令來查看單元測試覆蓋率。還是以 Fibonacci 函數(shù)的單元測試為例,通過一行命令即可查看它的單元測試覆蓋率。

? go test -v --coverprofile=ch18.cover ./ch18

這行命令包括 --coverprofile 這個 Flag,它可以得到一個單元測試覆蓋率文件,運行這行命令還可以同時看到測試覆蓋率。Fibonacci 函數(shù)的測試覆蓋率如下:

PASS
coverage: 85.7% of statements
ok      gotour/ch18     0.367s  coverage: 85.7% of statements

可以看到,測試覆蓋率為 85.7%。從這個數(shù)字來看,F(xiàn)ibonacci 函數(shù)應(yīng)該沒有被全面地測試,這時候就需要查看詳細(xì)的單元測試覆蓋率報告了。

運行如下命令,可以得到一個 HTML 格式的單元測試覆蓋率報告:

? go tool cover -html=ch18.cover -o=ch18.html

命令運行后,會在當(dāng)前目錄下生成一個 ch18.html 文件,使用瀏覽器打開它,可以看到圖中的內(nèi)容:

單元測試覆蓋率報告

紅色標(biāo)記的部分是沒有測試到的,綠色標(biāo)記的部分是已經(jīng)測試到的。這就是單元測試覆蓋率報告的好處,通過它你可以很容易地檢測自己寫的單元測試是否完全覆蓋。

根據(jù)報告,我再修改一下單元測試,把沒有覆蓋的代碼邏輯覆蓋到,代碼如下:

fsMap[-1] = 0

也就是說,由于圖中 n<0 的部分顯示為紅色,表示沒有測試到,所以我們需要再添加一組測試用例,用于測試 n<0 的情況。現(xiàn)在再運行這個單元測試,查看它的單元測試覆蓋率,就會發(fā)現(xiàn)已經(jīng)是 100% 了。

基準(zhǔn)測試

除了需要保證我們編寫的代碼的邏輯正確外,有時候還有性能要求。那么如何衡量代碼的性能呢?這就需要基準(zhǔn)測試了。

什么是基準(zhǔn)測試

基準(zhǔn)測試(Benchmark)是一項用于測量和評估軟件性能指標(biāo)的方法,主要用于評估你寫的代碼的性能。

Go 語言的基準(zhǔn)測試

Go 語言的基準(zhǔn)測試和單元測試規(guī)則基本一樣,只是測試函數(shù)的命名規(guī)則不一樣?,F(xiàn)在還以 Fibonacci 函數(shù)為例,演示 Go 語言基準(zhǔn)測試的使用。

Fibonacci 函數(shù)的基準(zhǔn)測試代碼如下:

ch18/main_test.go

func BenchmarkFibonacci(b *testing.B){
   for i:=0;i<b.N;i++{
      Fibonacci(10)
   }
}

這是一個非常簡單的 Go 語言基準(zhǔn)測試示例,它和單元測試的不同點如下:

  • 基準(zhǔn)測試函數(shù)必須以 Benchmark 開頭,必須是可導(dǎo)出的;
  • 函數(shù)的簽名必須接收一個指向 testing.B 類型的指針,并且不能返回任何值;
  • 最后的 for 循環(huán)很重要,被測試的代碼要放到循環(huán)里;
  • b.N 是基準(zhǔn)測試框架提供的,表示循環(huán)的次數(shù),因為需要反復(fù)調(diào)用測試的代碼,才可以評估性能。

寫好了基準(zhǔn)測試,就可以通過如下命令來測試 Fibonacci 函數(shù)的性能:

? go test -bench=. ./ch18
goos: darwin
goarch: amd64
pkg: gotour/ch18
BenchmarkFibonacci-8     3461616               343 ns/op
PASS
ok      gotour/ch18     2.230s

運行基準(zhǔn)測試也要使用 go test 命令,不過要加上 -bench 這個 Flag,它接受一個表達(dá)式作為參數(shù),以匹配基準(zhǔn)測試的函數(shù),"."表示運行所有基準(zhǔn)測試。

下面著重解釋輸出的結(jié)果。看到函數(shù)后面的 -8 了嗎?這個表示運行基準(zhǔn)測試時對應(yīng)的 GOMAXPROCS 的值。接著的 3461616 表示運行 for 循環(huán)的次數(shù),也就是調(diào)用被測試代碼的次數(shù),最后的 343 ns/op 表示每次需要花費 343 納秒。

基準(zhǔn)測試的時間默認(rèn)是 1 秒,也就是 1 秒調(diào)用 3461616 次、每次調(diào)用花費 343 納秒。如果想讓測試運行的時間更長,可以通過 -benchtime 指定,比如 3 秒,代碼如下所示:

go test -bench=. -benchtime=3s ./ch18

計時方法

進(jìn)行基準(zhǔn)測試之前會做一些準(zhǔn)備,比如構(gòu)建測試數(shù)據(jù)等,這些準(zhǔn)備也需要消耗時間,所以需要把這部分時間排除在外。這就需要通過 ResetTimer 方法重置計時器,示例代碼如下:

func BenchmarkFibonacci(b *testing.B) {
   n := 10
   b.ResetTimer() //重置計時器
   for i := 0; i < b.N; i++ {
      Fibonacci(n)
   }
}

這樣可以避免因為準(zhǔn)備數(shù)據(jù)耗時造成的干擾。

除了 ResetTimer 方法外,還有 StartTimer 和 StopTimer 方法,幫你靈活地控制什么時候開始計時、什么時候停止計時。

內(nèi)存統(tǒng)計

在基準(zhǔn)測試時,還可以統(tǒng)計每次操作分配內(nèi)存的次數(shù),以及每次操作分配的字節(jié)數(shù),這兩個指標(biāo)可以作為優(yōu)化代碼的參考。要開啟內(nèi)存統(tǒng)計也比較簡單,代碼如下,即通過 ReportAllocs() 方法:

func BenchmarkFibonacci(b *testing.B) {
   n := 10
   b.ReportAllocs() //開啟內(nèi)存統(tǒng)計
   b.ResetTimer() //重置計時器
   for i := 0; i < b.N; i++ {
      Fibonacci(n)
   }
}

現(xiàn)在再運行這個基準(zhǔn)測試,就可以看到如下結(jié)果:

? go test -bench=.  ./ch18
goos: darwin
goarch: amd64
pkg: gotour/ch18
BenchmarkFibonacci-8  2486265  486 ns/op  0 B/op  0 allocs/op
PASS
ok      gotour/ch18     2.533s

可以看到相比原來的基準(zhǔn)測試多了兩個指標(biāo),分別是 0 B/op 和 0 allocs/op。前者表示每次操作分配了多少字節(jié)的內(nèi)存,后者表示每次操作分配內(nèi)存的次數(shù)。這兩個指標(biāo)可以作為代碼優(yōu)化的參考,盡可能地越小越好。

小提示:以上兩個指標(biāo)是否越小越好?這是不一定的,因為有時候代碼實現(xiàn)需要空間換時間,所以要根據(jù)自己的具體業(yè)務(wù)而定,做到在滿足業(yè)務(wù)的情況下越小越好。

并發(fā)基準(zhǔn)測試

除了普通的基準(zhǔn)測試外,Go 語言還支持并發(fā)基準(zhǔn)測試,你可以測試在多個 goroutine 并發(fā)下代碼的性能。還是以 Fibonacci 為例,它的并發(fā)基準(zhǔn)測試代碼如下:

func BenchmarkFibonacciRunParallel(b *testing.B) {
   n := 10
   b.RunParallel(func(pb *testing.PB) {
      for pb.Next() {
         Fibonacci(n)
      }
   })
}

可以看到,Go 語言通過 RunParallel 方法運行并發(fā)基準(zhǔn)測試。RunParallel 方法會創(chuàng)建多個 goroutine,并將 b.N 分配給這些 goroutine 執(zhí)行。

基準(zhǔn)測試實戰(zhàn)

相信你已經(jīng)理解了 Go 語言的基準(zhǔn)測試,也學(xué)會了如何使用,現(xiàn)在我以一個實戰(zhàn)幫你復(fù)習(xí)。

還是以 Fibonacci 函數(shù)為例,通過前面小節(jié)的基準(zhǔn)測試,會發(fā)現(xiàn)它并沒有分配新的內(nèi)存,也就是說 Fibonacci 函數(shù)慢并不是因為內(nèi)存,排除掉這個原因,就可以歸結(jié)為所寫的算法問題了。

在遞歸運算中,一定會有重復(fù)計算,這是影響遞歸的主要因素。解決重復(fù)計算可以使用緩存,把已經(jīng)計算好的結(jié)果保存起來,就可以重復(fù)使用了。

基于這個思路,我將 Fibonacci 函數(shù)的代碼進(jìn)行如下修改:

//緩存已經(jīng)計算的結(jié)果
var cache = map[int]int{}
func Fibonacci(n int) int {
   if v, ok := cache[n]; ok {
      return v
   }
   result := 0
   switch {
   case n < 0:
      result = 0
   case n == 0:
      result = 0
   case n == 1:
      result = 1
   default:
      result = Fibonacci(n-1) + Fibonacci(n-2)
   }
   cache[n] = result
   return result
}

這組代碼的核心在于采用一個 map 將已經(jīng)計算好的結(jié)果緩存、便于重新使用。改造后,我再來運行基準(zhǔn)測試,看看剛剛優(yōu)化的效果,如下所示:

BenchmarkFibonacci-8  97823403  11.7 ns/op

可以看到,結(jié)果為 11.7 納秒,相比優(yōu)化前的 343 納秒,性能足足提高了 28 倍。

總結(jié)

單元測試是保證代碼質(zhì)量的好方法,但單元測試也不是萬能的,使用它可以降低 Bug 率,但也不要完全依賴。除了單元測試外,還可以輔以 Code Review、人工測試等手段更好地保證代碼質(zhì)量。

在這節(jié)課的最后給你留個練習(xí)題:在運行 go test 命令時,使用 -benchmem 這個 Flag 進(jìn)行內(nèi)存統(tǒng)計。

以上就是詳解Go 語言如何通過測試保證質(zhì)量的詳細(xì)內(nèi)容,更多關(guān)于Go 語言測試保證質(zhì)量的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解Golang實現(xiàn)http重定向https的方式

    詳解Golang實現(xiàn)http重定向https的方式

    這篇文章主要介紹了詳解Golang實現(xiàn)http重定向https的方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Go語言MySQLCURD數(shù)據(jù)庫操作示例詳解

    Go語言MySQLCURD數(shù)據(jù)庫操作示例詳解

    這篇文章主要為大家介紹了Go語言MySQLCURD數(shù)據(jù)庫操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 解析Go?中的?rune?類型

    解析Go?中的?rune?類型

    rune類型是?Go?語言的一種特殊數(shù)字類型,Go?語言通過rune處理中文,支持國際化多語言,本文給大家介紹Go?中的?rune?類型,感興趣的朋友一起看看吧
    2022-03-03
  • 如何使用大學(xué)教育郵箱下載golang等軟件(推薦)

    如何使用大學(xué)教育郵箱下載golang等軟件(推薦)

    這篇文章主要介紹了如何使用大學(xué)教育郵箱下載goland等軟件,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • Go語言TCP從原理到代碼實現(xiàn)詳解

    Go語言TCP從原理到代碼實現(xiàn)詳解

    這篇文章主要為大家介紹了Go語言TCP從原理到代碼實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go語言并發(fā)之Sync包的6個關(guān)鍵概念總結(jié)

    Go語言并發(fā)之Sync包的6個關(guān)鍵概念總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語言并發(fā)中Sync包的6個關(guān)鍵概念,文中的示例代碼講解詳細(xì),對我們深入學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2023-05-05
  • Go map排序的實現(xiàn)示例

    Go map排序的實現(xiàn)示例

    map默認(rèn)是無序的,不管是按照key還是按照value默認(rèn)都不排序,本文主要介紹了Go map排序的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • golang判斷結(jié)構(gòu)體為空的問題

    golang判斷結(jié)構(gòu)體為空的問題

    這篇文章主要介紹了golang判斷結(jié)構(gòu)體為空的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • gin 獲取post請求的json body操作

    gin 獲取post請求的json body操作

    這篇文章主要介紹了gin 獲取post請求的json body操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • golang高并發(fā)的深入理解

    golang高并發(fā)的深入理解

    golang從語言級別上對并發(fā)提供了支持,而且在啟動并發(fā)的方式上直接添加了語言級的關(guān)鍵字。下面這篇文章主要給大家介紹了關(guān)于golang高并發(fā)的相關(guān)資料,需要的朋友可以參考下
    2019-03-03

最新評論