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

Go語言單元測試模擬服務請求和接口返回

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

前言

這是Go單元測試從入門到放棄系列教程的第1篇,介紹了如何使用httptestgock工具進行網絡測試。

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

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

httptest

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

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

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

//?gin.go
package?httptest_demo
import?(
?"fmt"
?"net/http"
?"github.com/gin-gonic/gin"
)
//?Param?請求參數
type?Param?struct?{
?Name?string?`json:"name"`
}
//?helloHandler?/hello請求處理函數
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
}

現在我們需要為helloHandler函數編寫單元測試,這種情況下我們就可以使用httptest這個工具mock一個HTTP請求和響應記錄器,讓我們的 server 端接收并處理我們 mock 的HTTP請求,同時使用響應記錄器來記錄 server 端返回的響應內容。

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

//?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)?{
?//?定義兩個測試用例
?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一個HTTP請求
???req?:=?httptest.NewRequest(
????"POST",??????????????????????//?請求方法
????"/hello",????????????????????//?請求URL
????strings.NewReader(tt.param),?//?請求參數
???)
???//?mock一個響應記錄器
???w?:=?httptest.NewRecorder()
???//?讓server端處理mock請求并記錄返回的響應內容
???r.ServeHTTP(w,?req)
???//?校驗狀態(tài)碼是否符合預期
???assert.Equal(t,?http.StatusOK,?w.Code)
???//?解析并檢驗響應內容是否復合預期
???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í)行單元測試,查看測試結果

? 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

通過這個示例我們就掌握了如何使用httptest在HTTP Server服務中為請求處理函數編寫單元測試了。

gock

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

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

//?api.go
//?ReqParam?API請求參數
type?ReqParam?struct?{
?X?int?`json:"x"`
}
//?Result?API返回結果
type?Result?struct?{
?Value?int?`json:"value"`
}
func?GetResultByAPI(x,?y?int)?int?{
?p?:=?&ReqParam{X:?x}
?b,?_?:=?json.Marshal(p)
?//?調用其他服務的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
?}
?//?這里是對API返回的數據做一些邏輯處理
?return?ret.Value?+?y
}

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

這里推薦使用gock這個庫。

安裝

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

使用示例

使用gock對外部API進行mock,即mock指定參數返回約定好的響應內容。下面的代碼中mock了兩組數據,組成了兩個測試用例。

//?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?請求外部api時傳參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})
?//?調用我們的業(yè)務函數
?res?:=?GetResultByAPI(1,?1)
?//?校驗返回結果是否符合預期
?assert.Equal(t,?res,?101)
?//?mock?請求外部api時傳參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})
?//?調用我們的業(yè)務函數
?res?=?GetResultByAPI(2,?2)
?//?校驗返回結果是否符合預期
?assert.Equal(t,?res,?202)
?assert.True(t,?gock.IsDone())?//?斷言mock被觸發(fā)
}

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

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

測試結果和預期的完全一致。

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

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

總結

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

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

相關文章

  • Go中的gRPC入門教程詳解

    Go中的gRPC入門教程詳解

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

    Golang 讀取并解析SQL文件的實現方法

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

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

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

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

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

    Golang項目搭配nginx部署反向代理負載均衡講解

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

    Go?gRPC教程實現Simple?RPC

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

    Golang 實現 RTP音視頻傳輸示例詳解

    這篇文章主要為大家介紹了Golang實現RTP音視頻傳輸的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Golang實現gRPC的Proxy的原理解析

    Golang實現gRPC的Proxy的原理解析

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

    golang字符串轉64位整數的示例代碼

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

    在Golang中使用iota案例詳解

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

最新評論

腾冲县| 琼中| 讷河市| 邯郸县| 武安市| 昔阳县| 通州市| 南靖县| 抚松县| 南和县| 天镇县| 麻阳| 山阳县| 修文县| 张家界市| 蒲城县| 新龙县| 长汀县| 陵川县| 墨竹工卡县| 宜君县| 台前县| 河北省| 江津市| 鄂伦春自治旗| 黎川县| 蛟河市| 马关县| 汉阴县| 新沂市| 同德县| 吉水县| 盐山县| 京山县| 新竹市| 雅安市| 普陀区| 琼海市| 延边| 苏州市| 肥城市|