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

Go語言單元測試模擬服務(wù)請(qǐng)求和接口返回

 更新時(shí)間:2022年06月21日 15:49:33   作者:李文周  
這篇文章主要為大家介紹了Go語言單元測試模擬服務(wù)請(qǐng)求和接口返回示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

這是Go單元測試從入門到放棄系列教程的第1篇,介紹了如何使用httptestgock工具進(jìn)行網(wǎng)絡(luò)測試。

在上一篇《Go單元測試從入門到放棄—0.單元測試基礎(chǔ)》中,我們介紹了Go語言編寫單元測試的基礎(chǔ)內(nèi)容。

而實(shí)際工作中的業(yè)務(wù)場景往往會(huì)比較復(fù)雜,無論我們的代碼是作為server端對(duì)外提供服務(wù)或者還是我們依賴別人提供的網(wǎng)絡(luò)服務(wù)(調(diào)用別人提供的API接口)的場景,我們通常都不想在測試過程中真正的建立網(wǎng)絡(luò)連接。本文就專門介紹如何在上述兩種場景下mock網(wǎng)絡(luò)測試。

httptest

在Web開發(fā)場景下的單元測試,如果涉及到HTTP請(qǐng)求推薦大家使用Go標(biāo)準(zhǔn)庫 net/http/httptest 進(jìn)行測試,能夠顯著提高測試效率。

在這一小節(jié),我們以常見的gin框架為例,演示如何為 http server 編寫單元測試。

假設(shè)我們的業(yè)務(wù)邏輯是搭建一個(gè)http server端,對(duì)外提供HTTP服務(wù)。我們編寫了一個(gè)helloHandler函數(shù),用來處理用戶請(qǐng)求。

//?gin.go
package?httptest_demo
import?(
?"fmt"
?"net/http"
?"github.com/gin-gonic/gin"
)
//?Param?請(qǐng)求參數(shù)
type?Param?struct?{
?Name?string?`json:"name"`
}
//?helloHandler?/hello請(qǐng)求處理函數(shù)
func?helloHandler(c?*gin.Context)?{
?var?p?Param
?if?err?:=?c.ShouldBindJSON(&p);?err?!=?nil?{
??c.JSON(http.StatusOK,?gin.H{
???"msg":?"we?need?a?name",
??})
??return
?}
?c.JSON(http.StatusOK,?gin.H{
??"msg":?fmt.Sprintf("hello?%s",?p.Name),
?})
}
//?SetupRouter?路由
func?SetupRouter()?*gin.Engine?{
?router?:=?gin.Default()
?router.POST("/hello",?helloHandler)
?return?router
}

現(xiàn)在我們需要為helloHandler函數(shù)編寫單元測試,這種情況下我們就可以使用httptest這個(gè)工具mock一個(gè)HTTP請(qǐng)求和響應(yīng)記錄器,讓我們的 server 端接收并處理我們 mock 的HTTP請(qǐng)求,同時(shí)使用響應(yīng)記錄器來記錄 server 端返回的響應(yīng)內(nèi)容。

單元測試的示例代碼如下:

//?gin_test.go
package?httptest_demo
import?(
?"encoding/json"
?"net/http"
?"net/http/httptest"
?"strings"
?"testing"
?"github.com/stretchr/testify/assert"
)
func?Test_helloHandler(t?*testing.T)?{
?//?定義兩個(gè)測試用例
?tests?:=?[]struct?{
??name???string
??param??string
??expect?string
?}{
??{"base?case",?`{"name":?"liwenzhou"}`,?"hello?liwenzhou"},
??{"bad?case",?"",?"we?need?a?name"},
?}
?r?:=?SetupRouter()
?for?_,?tt?:=?range?tests?{
??t.Run(tt.name,?func(t?*testing.T)?{
???//?mock一個(gè)HTTP請(qǐng)求
???req?:=?httptest.NewRequest(
????"POST",??????????????????????//?請(qǐng)求方法
????"/hello",????????????????????//?請(qǐng)求URL
????strings.NewReader(tt.param),?//?請(qǐng)求參數(shù)
???)
???//?mock一個(gè)響應(yīng)記錄器
???w?:=?httptest.NewRecorder()
???//?讓server端處理mock請(qǐng)求并記錄返回的響應(yīng)內(nèi)容
???r.ServeHTTP(w,?req)
???//?校驗(yàn)狀態(tài)碼是否符合預(yù)期
???assert.Equal(t,?http.StatusOK,?w.Code)
???//?解析并檢驗(yàn)響應(yīng)內(nèi)容是否復(fù)合預(yù)期
???var?resp?map[string]string
???err?:=?json.Unmarshal([]byte(w.Body.String()),?&resp)
???assert.Nil(t,?err)
???assert.Equal(t,?tt.expect,?resp["msg"])
??})
?}
}

執(zhí)行單元測試,查看測試結(jié)果

? go test -v
=== RUN   Test_helloHandler
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)
[GIN-debug] POST   /hello                    --> golang-unit-test-demo/httptest_demo.helloHandler (3 handlers)
=== RUN   Test_helloHandler/base_case
[GIN] 2021/09/14 - 22:00:04 | 200 |     164.839µs |       192.0.2.1 | POST     "/hello"
=== RUN   Test_helloHandler/bad_case
[GIN] 2021/09/14 - 22:00:04 | 200 |      23.723µs |       192.0.2.1 | POST     "/hello"
--- PASS: Test_helloHandler (0.00s)
    --- PASS: Test_helloHandler/base_case (0.00s)
    --- PASS: Test_helloHandler/bad_case (0.00s)
PASS
ok      golang-unit-test-demo/httptest_demo     0.055s

通過這個(gè)示例我們就掌握了如何使用httptest在HTTP Server服務(wù)中為請(qǐng)求處理函數(shù)編寫單元測試了。

gock

上面的示例介紹了如何在HTTP Server服務(wù)類場景下為請(qǐng)求處理函數(shù)編寫單元測試,那么如果我們是在代碼中請(qǐng)求外部API的場景(比如通過API調(diào)用其他服務(wù)獲取返回值)又該怎么編寫單元測試呢?

例如,我們有以下業(yè)務(wù)邏輯代碼,依賴外部API:http://your-api.com/post提供的數(shù)據(jù)。

//?api.go
//?ReqParam?API請(qǐng)求參數(shù)
type?ReqParam?struct?{
?X?int?`json:"x"`
}
//?Result?API返回結(jié)果
type?Result?struct?{
?Value?int?`json:"value"`
}
func?GetResultByAPI(x,?y?int)?int?{
?p?:=?&ReqParam{X:?x}
?b,?_?:=?json.Marshal(p)
?//?調(diào)用其他服務(wù)的API
?resp,?err?:=?http.Post(
??"http://your-api.com/post",
??"application/json",
??bytes.NewBuffer(b),
?)
?if?err?!=?nil?{
??return?-1
?}
?body,?_?:=?ioutil.ReadAll(resp.Body)
?var?ret?Result
?if?err?:=?json.Unmarshal(body,?&ret);?err?!=?nil?{
??return?-1
?}
?//?這里是對(duì)API返回的數(shù)據(jù)做一些邏輯處理
?return?ret.Value?+?y
}

在對(duì)類似上述這類業(yè)務(wù)代碼編寫單元測試的時(shí)候,如果不想在測試過程中真正去發(fā)送請(qǐng)求或者依賴的外部接口還沒有開發(fā)完成時(shí),我們可以在單元測試中對(duì)依賴的API進(jìn)行mock。

這里推薦使用gock這個(gè)庫。

安裝

go?get?-u?gopkg.in/h2non/gock.v1

使用示例

使用gock對(duì)外部API進(jìn)行mock,即mock指定參數(shù)返回約定好的響應(yīng)內(nèi)容。下面的代碼中mock了兩組數(shù)據(jù),組成了兩個(gè)測試用例。

//?api_test.go
package?gock_demo
import?(
?"testing"
?"github.com/stretchr/testify/assert"
?"gopkg.in/h2non/gock.v1"
)
func?TestGetResultByAPI(t?*testing.T)?{
?defer?gock.Off()?//?測試執(zhí)行后刷新掛起的mock
?//?mock?請(qǐng)求外部api時(shí)傳參x=1返回100
?gock.New("http://your-api.com").
??Post("/post").
??MatchType("json").
??JSON(map[string]int{"x":?1}).
??Reply(200).
??JSON(map[string]int{"value":?100})
?//?調(diào)用我們的業(yè)務(wù)函數(shù)
?res?:=?GetResultByAPI(1,?1)
?//?校驗(yàn)返回結(jié)果是否符合預(yù)期
?assert.Equal(t,?res,?101)
?//?mock?請(qǐng)求外部api時(shí)傳參x=2返回200
?gock.New("http://your-api.com").
??Post("/post").
??MatchType("json").
??JSON(map[string]int{"x":?2}).
??Reply(200).
??JSON(map[string]int{"value":?200})
?//?調(diào)用我們的業(yè)務(wù)函數(shù)
?res?=?GetResultByAPI(2,?2)
?//?校驗(yàn)返回結(jié)果是否符合預(yù)期
?assert.Equal(t,?res,?202)
?assert.True(t,?gock.IsDone())?//?斷言mock被觸發(fā)
}

執(zhí)行上面寫好的單元測試,看一下測試結(jié)果。

? go test -v
=== RUN   TestGetResultByAPI
--- PASS: TestGetResultByAPI (0.00s)
PASS
ok      golang-unit-test-demo/gock_demo 0.054s

測試結(jié)果和預(yù)期的完全一致。

在這個(gè)示例中,為了讓大家能夠清晰的了解gock的使用,我特意沒有使用表格驅(qū)動(dòng)測試。給大家留一個(gè)小作業(yè):自己動(dòng)手把這個(gè)單元測試改寫成表格驅(qū)動(dòng)測試的風(fēng)格,就當(dāng)做是對(duì)最近兩篇教程的復(fù)習(xí)和測驗(yàn)。

?這里網(wǎng)管來當(dāng)下課代表,大家可以把這個(gè)作業(yè)在公眾號(hào)私信發(fā)我,一起交流下答案。如果想摸魚也可以直接找我要答案,不過不給白嫖哦,必須來個(gè)三連:)。

總結(jié)

在日常工作開發(fā)中為代碼編寫單元測試時(shí)如何處理外部依賴是最常見的問題,本文介紹了如何使用httptestgock工具mock相關(guān)依賴。

后面我們將更進(jìn)一步,詳細(xì)介紹針對(duì)依賴MySQL和Redis的場景如何編寫單元測試,更多關(guān)于Go單元測試模擬服務(wù)請(qǐng)求和接口返回的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 在 Golang 中實(shí)現(xiàn) Cache::remember 方法詳解

    在 Golang 中實(shí)現(xiàn) Cache::remember 方法詳解

    這篇文章主要介紹了在 Golang 中實(shí)現(xiàn) Cache::remember 方法詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • GO語言延遲函數(shù)defer用法分析

    GO語言延遲函數(shù)defer用法分析

    這篇文章主要介紹了GO語言延遲函數(shù)defer用法,較為詳細(xì)的分析了GO語言的特性與具體用法,并給出了一個(gè)比較典型的應(yīng)用實(shí)例,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • golang mapstructure庫的具體使用

    golang mapstructure庫的具體使用

    mapstructure用于將通用的map[string]interface{}解碼到對(duì)應(yīng)的 Go 結(jié)構(gòu)體中,或者執(zhí)行相反的操作,本文主要介紹了golang mapstructure庫的具體使用,感興趣的可以了解一下
    2023-09-09
  • GO文件創(chuàng)建及讀寫操作示例詳解

    GO文件創(chuàng)建及讀寫操作示例詳解

    這篇文章主要為大家介紹了GO文件創(chuàng)建及讀寫操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • go的strings用法小結(jié)

    go的strings用法小結(jié)

    strings 是 Go 語言標(biāo)準(zhǔn)庫中提供的一個(gè)包,用于處理字符串相關(guān)的操作,本文主要介紹了go的strings用法小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • Golang庫插件注冊(cè)加載機(jī)制的問題

    Golang庫插件注冊(cè)加載機(jī)制的問題

    這篇文章主要介紹了Golang庫插件注冊(cè)加載機(jī)制,這里說的插件并不是指的golang原生的可以在buildmode中加載指定so文件的那種加載機(jī)制,需要的朋友可以參考下
    2022-03-03
  • Golang實(shí)現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map

    Golang實(shí)現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map

    在項(xiàng)目實(shí)踐中,有時(shí)候我們需要將struct結(jié)構(gòu)體轉(zhuǎn)為map映射表,然后基于map做數(shù)據(jù)裁剪或操作。那么下面我來介紹下常用的兩種轉(zhuǎn)換方式,希望對(duì)大家有所幫助
    2023-01-01
  • 詳解Go語言中init的使用與常見應(yīng)用場景

    詳解Go語言中init的使用與常見應(yīng)用場景

    Go?中有一個(gè)特別的?init()?函數(shù),它主要用于包的初始化,這篇文章將以此為主題介紹?Go?中?init()?函數(shù)的使用和常見使用場景,希望對(duì)大家有所幫助
    2024-02-02
  • Golang當(dāng)中的定時(shí)器實(shí)例詳解

    Golang當(dāng)中的定時(shí)器實(shí)例詳解

    這篇文章主要給大家介紹了關(guān)于Golang當(dāng)中定時(shí)器的相關(guān)資料,定時(shí)器的實(shí)現(xiàn)大家應(yīng)該都遇到過,最近在學(xué)習(xí)golang,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • go 生成器模式的具體使用

    go 生成器模式的具體使用

    生成器是一種創(chuàng)建型設(shè)計(jì)模式,使你能夠分步驟創(chuàng)建復(fù)雜對(duì)象,本文主要介紹了go生成器模式的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01

最新評(píng)論