最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

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

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

httptest

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

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

假設(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ù)編寫單元測(cè)試,這種情況下我們就可以使用httptest這個(gè)工具mock一個(gè)HTTP請(qǐng)求和響應(yīng)記錄器,讓我們的 server 端接收并處理我們 mock 的HTTP請(qǐng)求,同時(shí)使用響應(yīng)記錄器來記錄 server 端返回的響應(yīng)內(nèi)容。

單元測(cè)試的示例代碼如下:

//?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è)測(cè)試用例
?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í)行單元測(cè)試,查看測(cè)試結(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ù)編寫單元測(cè)試了。

gock

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

例如,我們有以下業(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ù)代碼編寫單元測(cè)試的時(shí)候,如果不想在測(cè)試過程中真正去發(fā)送請(qǐng)求或者依賴的外部接口還沒有開發(fā)完成時(shí),我們可以在單元測(cè)試中對(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è)測(cè)試用例。

//?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()?//?測(cè)試執(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í)行上面寫好的單元測(cè)試,看一下測(cè)試結(jié)果。

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

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

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

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

總結(jié)

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

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

相關(guān)文章

  • Go中的gRPC入門教程詳解

    Go中的gRPC入門教程詳解

    本文詳細(xì)講解了Go中的gRPC入門教程,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • Golang 讀取并解析SQL文件的實(shí)現(xiàn)方法

    Golang 讀取并解析SQL文件的實(shí)現(xiàn)方法

    本文介紹了如何使用Go語言編寫一個(gè)簡單的函數(shù),用于讀取并解析SQL文件,通過一個(gè)函數(shù),我們可以輕松地將SQL文件中的語句提取出來,進(jìn)行后續(xù)的操作,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • go語言實(shí)現(xiàn)簡易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能

    go語言實(shí)現(xiàn)簡易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能

    這篇文章主要介紹了go語言實(shí)現(xiàn)簡易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • go-zero?組件布隆過濾器使用示例詳解

    go-zero?組件布隆過濾器使用示例詳解

    這篇文章主要為大家介紹了go-zero組件介紹之布隆過濾器使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Golang項(xiàng)目搭配nginx部署反向代理負(fù)載均衡講解

    Golang項(xiàng)目搭配nginx部署反向代理負(fù)載均衡講解

    這篇文章主要為大家介紹了Golang項(xiàng)目搭配nginx部署正反向代理負(fù)載均衡講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go?gRPC教程實(shí)現(xiàn)Simple?RPC

    Go?gRPC教程實(shí)現(xiàn)Simple?RPC

    這篇文章主要為大家介紹了Go?gRPC教程實(shí)現(xiàn)Simple?RPC示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Golang 實(shí)現(xiàn) RTP音視頻傳輸示例詳解

    Golang 實(shí)現(xiàn) RTP音視頻傳輸示例詳解

    這篇文章主要為大家介紹了Golang實(shí)現(xiàn)RTP音視頻傳輸?shù)氖纠斀?,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Golang實(shí)現(xiàn)gRPC的Proxy的原理解析

    Golang實(shí)現(xiàn)gRPC的Proxy的原理解析

    gRPC是Google開始的一個(gè)RPC服務(wù)框架, 是英文全名為Google Remote Procedure Call的簡稱,廣泛的應(yīng)用在有RPC場景的業(yè)務(wù)系統(tǒng)中,這篇文章主要介紹了Golang實(shí)現(xiàn)gRPC的Proxy的原理,需要的朋友可以參考下
    2021-09-09
  • golang字符串轉(zhuǎn)64位整數(shù)的示例代碼

    golang字符串轉(zhuǎn)64位整數(shù)的示例代碼

    這篇文章主要介紹了golang字符串轉(zhuǎn)64位整數(shù),在Go語言中,可以使用strconv包中的ParseInt函數(shù)將字符串轉(zhuǎn)換為64位整數(shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • 在Golang中使用iota案例詳解

    在Golang中使用iota案例詳解

    在Go語言中,iota是一個(gè)預(yù)定義的標(biāo)識(shí)符,用于在常量聲明中生成連續(xù)的遞增值,iota的值從0開始,每次在常量聲明中使用時(shí)遞增,本就給大家講解一下Golang中iota的使用案例,感興趣的同學(xué)跟著小編一起來看看吧
    2023-07-07

最新評(píng)論

横山县| 板桥市| 石渠县| 浦北县| 太仓市| 洮南市| 盱眙县| 巴楚县| 万源市| 东乡族自治县| 五华县| 云阳县| 玉屏| 西乌| 临漳县| 盖州市| 新平| 和田市| 酒泉市| 息烽县| 县级市| 富裕县| 伊通| 通山县| 闸北区| 伊金霍洛旗| 台州市| 耿马| 庐江县| 白河县| 抚州市| 昌都县| 中江县| 基隆市| 凌海市| 泸溪县| 定西市| 富蕴县| 高雄市| 镇巴县| 甘孜县|