Go語言之單元測試-創(chuàng)新互聯(lián)

什么是單元測試

相信我們做程序員的,對單元測試都不陌生。單元測試一般是用來測試我們的代碼邏輯有沒有問題,有沒有按照我們期望的運(yùn)行,以保證代碼質(zhì)量。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),金水企業(yè)網(wǎng)站建設(shè),金水品牌網(wǎng)站建設(shè),網(wǎng)站定制,金水網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,金水網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

大多數(shù)的單元測試,都是對某一個(gè)函數(shù)方法進(jìn)行測試,以盡可能的保證沒有問題或者問題可被我們預(yù)知。為了達(dá)到這個(gè)目的,我們可以使用各種手段、邏輯,模擬不同的場景進(jìn)行測試。

這里我們在package main里定義一個(gè)函數(shù)Add,求兩個(gè)數(shù)之和的函數(shù),然后我們使用單元測試進(jìn)行求和邏輯測試。

main.go

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

main_test.go

func TestAdd(t *testing.T) {
   sum := Add(1,2)
   if sum == 3 {
     t.Log("the result is ok")
   } else {
     t.Fatal("the result is wrong")
   }
}

然后我們在終端的項(xiàng)目目錄下運(yùn)行g(shù)o test -v就可以看到測試結(jié)果了。

?  hello go test -v
=== RUN  TestAdd
--- PASS: TestAdd (0.00s)     main_test.go:26: the result is ok PASS ok    flysnow.org/hello    0.007s

有測試成功PASS標(biāo)記,并且打印出我們想要的結(jié)果。

  • Go語言為我們提供了測試框架,以便幫助我們更容易的進(jìn)行單元測試,但是要使用這個(gè)框架,需要遵循如下幾點(diǎn)規(guī)則:


  • 含有單元測試代碼的go文件必須以_test.go結(jié)尾,Go語言測試工具只認(rèn)符合這個(gè)規(guī)則的文件。


  • 單元測試文件名_test.go前面的部分最好是被測試的方法所在go文件的文件名,比如例子中是main_test.go,因?yàn)闇y試的Add函數(shù),在main.go文件里。


  • 單元測試的函數(shù)名必須以Test開頭,是可導(dǎo)出公開的函數(shù)。


  • 測試函數(shù)的簽名必須接收一個(gè)指向testing.T類型的指針,并且不能返回任何值。


  • 函數(shù)名最好是Test+要測試的方法函數(shù)名,比如例子中是TestAdd,表示測試的是Add這個(gè)這個(gè)函數(shù)。


遵循以上規(guī)則,我們就可以很容易的編寫單元測試了,單元測試的重點(diǎn)在于測試代碼的邏輯,場景等,以便盡可能的測試全面,保障代碼質(zhì)量邏輯。

表組測試

還有一種單元測試方法叫表組測試,這個(gè)和基本的單元測試非常相似,只不過它是有好幾個(gè)不同的輸入以及輸出組成的一組單元測試。

比如上個(gè)例子中,我們測試了1+2,如果我們再加上3+4,9+2等,這就有了好幾個(gè)輸入,同時(shí)對應(yīng)的也有好幾個(gè)輸出,這種一次性測試很多個(gè)輸入輸出場景的測試,就是表組測試。

func TestAdd(t *testing.T) {
   sum := Add(1,2)
   if sum == 3 {
     t.Log("the result is ok")
   } else {
     t.Fatal("the result is wrong")
   }

   sum=Add(3,4)   
   if sum == 7 {
     t.Log("the result is ok")
   } else {
     t.Fatal("the result is wrong")
   }
}

模擬調(diào)用

單元測試的原則,就是你所測試的函數(shù)方法,不要受到所依賴環(huán)境的影響,比如網(wǎng)絡(luò)訪問等,因?yàn)橛袝r(shí)候我們運(yùn)行單元測試的時(shí)候,并沒有聯(lián)網(wǎng),那么總不能讓單元測試因?yàn)檫@個(gè)失敗吧?所以這時(shí)候模擬網(wǎng)絡(luò)訪問就有必要了。

針對模擬網(wǎng)絡(luò)訪問,標(biāo)準(zhǔn)庫了提供了一個(gè)httptest包,可以讓我們模擬http的網(wǎng)絡(luò)調(diào)用,下面舉個(gè)例子了解使用。

首先我們創(chuàng)建一個(gè)處理HTTP請求的函數(shù),并注冊路由。

package commonimport (
   "net/http"
   "encoding/json")func Routes(){
   http.HandleFunc("/sendjson",SendJSON)}func SendJSON(rw http.ResponseWriter,r *http.Request){
   u := struct {
     Name string
   }{
     Name:"張三",
   }

   rw.Header().Set("Content-Type","application/json")
   rw.WriteHeader(http.StatusOK)
   json.NewEncoder(rw).Encode(u)
}

非常簡單,這里是一個(gè)/sendjsonAPI,當(dāng)我們訪問這個(gè)API時(shí),會返回一個(gè)JSON字符串?,F(xiàn)在我們對這個(gè)API服務(wù)進(jìn)行測試,但是我們又不能時(shí)時(shí)刻刻都啟動著服務(wù),所以這里就用到了外部終端對API的網(wǎng)絡(luò)訪問請求。

func init()  {
   common.Routes()}func TestSendJSON(t *testing.T){
   req,err:=http.NewRequest(http.MethodGet,"/sendjson",nil)
   if err!=nil {
     t.Fatal("創(chuàng)建Request失敗")
   }

   rw:=httptest.NewRecorder()
   http.DefaultServeMux.ServeHTTP(rw,req)

   log.Println("code:",rw.Code)

   log.Println("body:",rw.Body.String())
}

運(yùn)行這個(gè)單元測試,就可以看到我們訪問/sendjsonAPI的結(jié)果里,并且我們沒有啟動任何HTTP服務(wù)就達(dá)到了目的。這個(gè)主要利用httptest.NewRecorder()創(chuàng)建一個(gè)http.ResponseWriter,模擬了真實(shí)服務(wù)端的響應(yīng),這種響應(yīng)時(shí)通過調(diào)用http.DefaultServeMux.ServeHTTP方法觸發(fā)的。

還有一個(gè)模擬調(diào)用的方式,是真的在測試機(jī)上模擬一個(gè)服務(wù)器,然后進(jìn)行調(diào)用測試。

func mockServer() *httptest.Server {
   //API調(diào)用處理函數(shù)
   sendJson := func(rw http.ResponseWriter, r *http.Request) {
     u := struct {
       Name string
     }{
       Name: "張三",
     }

     rw.Header().Set("Content-Type", "application/json")
     rw.WriteHeader(http.StatusOK)
     json.NewEncoder(rw).Encode(u)
   }   
   //適配器轉(zhuǎn)換
   return httptest.NewServer(http.HandlerFunc(sendJson))
}
func TestSendJSON(t *testing.T) {   //創(chuàng)建一個(gè)模擬的服務(wù)器   server := mockServer()      defer server.Close()      //Get請求發(fā)往模擬服務(wù)器的地址   resq, err := http.Get(server.URL)      if err != nil {     t.Fatal("創(chuàng)建Get失敗")   }   defer resq.Body.Close()   log.Println("code:", resq.StatusCode)   json, err := ioutil.ReadAll(resq.Body)      if err != nil {     log.Fatal(err)   }   log.Printf("body:%s\n", json)
}

模擬服務(wù)器的創(chuàng)建使用的是httptest.NewServer函數(shù),它接收一個(gè)http.Handler處理API請求的接口。

代碼示例中使用了Hander的適配器模式,http.HandlerFunc是一個(gè)函數(shù)類型,實(shí)現(xiàn)了http.Handler接口,這里是強(qiáng)制類型轉(zhuǎn)換,不是函數(shù)的調(diào)用。

這個(gè)創(chuàng)建的模擬服務(wù)器,監(jiān)聽的是本機(jī)IP127.0.0.1,端口是隨機(jī)的。接著我們發(fā)送Get請求的時(shí)候,不再發(fā)往/sendjson,而是模擬服務(wù)器的地址server.URL,剩下的就和訪問正常的URL一樣了,打印出結(jié)果即可。

測試覆蓋率

我們盡可能的模擬更多的場景來測試我們代碼的不同情況,但是有時(shí)候的確也有忘記測試的代碼,這時(shí)候我們就需要測試覆蓋率作為參考了。

由單元測試的代碼,觸發(fā)運(yùn)行到的被測試代碼的代碼行數(shù)占所有代碼行數(shù)的比例,被稱為測試覆蓋率,代碼覆蓋率不一定完全精準(zhǔn),但是可以作為參考,可以幫我們測量和我們預(yù)計(jì)的覆蓋率之間的差距,go test工具,就為我們提供了這么一個(gè)度量測試覆蓋率的能力。

main.go

func Tag(tag int){
   switch tag {   
   case 1:
     fmt.Println("Android")   
   case 2:
     fmt.Println("Go")   
   case 3:
     fmt.Println("Java")   
   default:
     fmt.Println("C")

   }
}

main_test.go

func TestTag(t *testing.T) {
   Tag(1)
   Tag(2)
}

現(xiàn)在我們使用go test工具運(yùn)行單元測試,和前幾次不一樣的是,我們要顯示測試覆蓋率,所以要多加一個(gè)參數(shù)-coverprofile,所以完整的命令為:go test -v -coverprofile=c.out,-coverprofile是指定生成的覆蓋率文件,例子中是c.out,這個(gè)文件一會我們會用到?,F(xiàn)在我們看終端輸出,已經(jīng)有了一個(gè)覆蓋率。

=== RUN  TestTag
Android
Go
--- PASS: TestTag (0.00s)
PASS coverage: 60.0% of statements ok    flysnow.org/hello    0.005s

coverage: 60.0% of statements,60% 的測試覆蓋率,還沒有到 100% ,那么我們看看還有那些代碼沒有被測試到。這就需要我們剛剛生成的測試覆蓋率文件c.out生成測試覆蓋率報(bào)告了。生成報(bào)告有g(shù)o為我們提供的工具,使用go tool cover -html=c.out -o=tag.html,即可生成一個(gè)名字為tag.html的HTML格式的測試覆蓋率報(bào)告,這里有詳細(xì)的信息告訴我們哪一行代碼測試到了,哪一行代碼沒有測試到。

從上圖中可以看到,標(biāo)記為綠色的代碼行已經(jīng)被測試了;標(biāo)記為紅色的還沒有測試到,有兩行的,現(xiàn)在我們根據(jù)沒有測試到的代碼邏輯,完善我的單元測試代碼即可。

func TestTag(t *testing.T) {
   Tag(1)
   Tag(2)
   Tag(3)
   Tag(6)
}

單元測試完善為如上代碼,再運(yùn)行單元測試,就可以看到測試覆蓋率已經(jīng)是 100% 了,大功告成。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

分享標(biāo)題:Go語言之單元測試-創(chuàng)新互聯(lián)
鏈接分享:http://muchs.cn/article6/dcjiig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、云服務(wù)器、營銷型網(wǎng)站建設(shè)、做網(wǎng)站動態(tài)網(wǎng)站、面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)