




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第Go語言單元測試模擬服務(wù)請求和接口返回目錄前言httptestgock安裝使用示例總結(jié)
前言
這是Go單元測試從入門到放棄系列教程的第1篇,介紹了如何使用httptest和gock工具進(jìn)行網(wǎng)絡(luò)測試。
在上一篇《Go單元測試從入門到放棄0.單元測試基礎(chǔ)》中,我們介紹了Go語言編寫單元測試的基礎(chǔ)內(nèi)容。
而實際工作中的業(yè)務(wù)場景往往會比較復(fù)雜,無論我們的代碼是作為server端對外提供服務(wù)或者還是我們依賴別人提供的網(wǎng)絡(luò)服務(wù)(調(diào)用別人提供的API接口)的場景,我們通常都不想在測試過程中真正的建立網(wǎng)絡(luò)連接。本文就專門介紹如何在上述兩種場景下mock網(wǎng)絡(luò)測試。
httptest
在Web開發(fā)場景下的單元測試,如果涉及到HTTP請求推薦大家使用Go標(biāo)準(zhǔn)庫net/http/httptest進(jìn)行測試,能夠顯著提高測試效率。
在這一小節(jié),我們以常見的gin框架為例,演示如何為httpserver編寫單元測試。
假設(shè)我們的業(yè)務(wù)邏輯是搭建一個httpserver端,對外提供HTTP服務(wù)。我們編寫了一個helloHandler函數(shù),用來處理用戶請求。
//
gin.go
package
httptest_demo
import
(
"fmt"
"net/http"
"/gin-gonic/gin"
//
Param
請求參數(shù)
type
Param
struct
{
Name
string
`json:"name"`
//
helloHandler
/hello請求處理函數(shù)
func
helloHandler(c
*gin.Context)
{
var
p
Param
if
err
:=
c.ShouldBindJSON(amp;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這個工具mock一個HTTP請求和響應(yīng)記錄器,讓我們的server端接收并處理我們mock的HTTP請求,同時使用響應(yīng)記錄器來記錄server端返回的響應(yīng)內(nèi)容。
單元測試的示例代碼如下:
//
gin_test.go
package
httptest_demo
import
(
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"/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(,
func(t
*testing.T)
{
//
mock一個HTTP請求
req
:=
httptest.NewRequest(
"POST",
//
請求方法
"/hello",
//
請求URL
strings.NewReader(tt.param),
//
請求參數(shù)
//
mock一個響應(yīng)記錄器
w
:=
httptest.NewRecorder()
//
讓server端處理mock請求并記錄返回的響應(yīng)內(nèi)容
r.ServeHTTP(w,
req)
//
校驗狀態(tài)碼是否符合預(yù)期
assert.Equal(t,
http.StatusOK,
w.Code)
//
解析并檢驗響應(yīng)內(nèi)容是否復(fù)合預(yù)期
var
resp
map[string]string
err
:=
json.Unmarshal([]byte(w.Body.String()),
amp;resp)
assert.Nil(t,
err)
assert.Equal(t,
tt.expect,
resp["msg"])
執(zhí)行單元測試,查看測試結(jié)果
?gotest-v
===RUNTest_helloHandler
[GIN-debug][WARNING]CreatinganEngineinstancewiththeLoggerandRecoverymiddlewarealreadyattached.
[GIN-debug][WARNING]Runningindebugmode.Switchtoreleasemodeinproduction.
-usingenv:exportGIN_MODE=release
-usingcode:gin.SetMode(gin.ReleaseMode)
[GIN-debug]POST/hello--golang-unit-test-demo/httptest_demo.helloHandler(3handlers)
===RUNTest_helloHandler/base_case
[GIN]2025/09/14-22:00:04|200|164.839s||POST/hello
===RUNTest_helloHandler/bad_case
[GIN]2025/09/14-22:00:04|200|23.723s||POST/hello
---PASS:Test_helloHandler(0.00s)
---PASS:Test_helloHandler/base_case(0.00s)
---PASS:Test_helloHandler/bad_case(0.00s)
PASS
okgolang-unit-test-demo/httptest_demo0.055s
通過這個示例我們就掌握了如何使用httptest在HTTPServer服務(wù)中為請求處理函數(shù)編寫單元測試了。
gock
上面的示例介紹了如何在HTTPServer服務(wù)類場景下為請求處理函數(shù)編寫單元測試,那么如果我們是在代碼中請求外部API的場景(比如通過API調(diào)用其他服務(wù)獲取返回值)又該怎么編寫單元測試呢?
例如,我們有以下業(yè)務(wù)邏輯代碼,依賴外部API:/post提供的數(shù)據(jù)。
//
api.go
//
ReqParam
API請求參數(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
:=
amp;ReqParam{X:
x}
b,
_
:=
json.Marshal(p)
//
調(diào)用其他服務(wù)的API
resp,
err
:=
http.Post(
"/post",
"application/json",
bytes.NewBuffer(b),
if
err
!=
nil
{
return
-1
body,
_
:=
ioutil.ReadAll(resp.Body)
var
ret
Result
if
err
:=
json.Unmarshal(body,
amp;ret);
err
!=
nil
{
return
-1
//
這里是對API返回的數(shù)據(jù)做一些邏輯處理
return
ret.Value
+
y
在對類似上述這類業(yè)務(wù)代碼編寫單元測試的時候,如果不想在測試過程中真正去發(fā)送請求或者依賴的外部接口還沒有開發(fā)完成時,我們可以在單元測試中對依賴的API進(jìn)行mock。
這里推薦使用gock這個庫。
安裝
go
get
-u
gopkg.in/h2non/gock.v1
使用示例
使用gock對外部API進(jìn)行mock,即mock指定參數(shù)返回約定好的響應(yīng)內(nèi)容。下面的代碼中mock了兩組數(shù)據(jù),組成了兩個測試用例。
//
api_test.go
package
gock_demo
import
(
"testing"
"/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("").
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)
//
校驗返回結(jié)果是否符合預(yù)期
assert.Equal(t,
res,
101)
//
mock
請求外部api時傳參x=2返回200
gock.New("").
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)
//
校驗返回結(jié)果是否符合預(yù)期
assert.Equal(t,
res,
202)
assert.True(t,
gock.IsDone())
//
斷言mock被觸發(fā)
執(zhí)行上面寫好的單元測試,看一下測試結(jié)果。
?gotest-v
===RUNTestGetResultByAPI
---PASS:TestGetResultByAPInbsp;(0.00s)
PASS
okgolang-unit-test-demo/gock_demo0.054s
測試結(jié)果和預(yù)期的完全一致。
在這個示例中,為了讓大家能夠清晰的了解gock的使用,我特意沒有使用表格驅(qū)動測試。給大家留一個小作業(yè):自己動手把這個單元測試改寫成表格驅(qū)動測試的風(fēng)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)療設(shè)備融資租賃中區(qū)塊鏈技術(shù)的便捷性體現(xiàn)
- 細(xì)胞膜-系統(tǒng)的邊界教學(xué)設(shè)計與反思
- app推廣服務(wù)合同樣本
- 親子活動基地合同范例
- 機器人焊接 10 項目五任務(wù)5.2教學(xué)設(shè)計
- 公共綠化養(yǎng)護合同范例
- 化學(xué)教學(xué)個人年度工作總結(jié)模版
- 光伏材料購銷合同范例
- 幼兒園小班暑期家訪工作總結(jié)模版
- 供貨附加合同范例
- 體外高頻熱療的護理
- JGJ79-2012 建筑地基處理技術(shù)規(guī)范
- 海康威視校招在線測評題庫
- 新編酒水知識與調(diào)酒
- 電網(wǎng)兩票培訓(xùn)課件
- 班級管理《班主任經(jīng)驗交流》課件
- 預(yù)防機車車輛傷害培訓(xùn)課件
- 《土地集約利用》課件
- 2024老舊小區(qū)改造質(zhì)量驗收規(guī)范
- 小學(xué)英語(完整版)現(xiàn)在進(jìn)行時練習(xí)題附答案
- 《畫幾何圖形》教學(xué)課件
評論
0/150
提交評論