Go語言單元測試模擬服務(wù)請求和接口返回_第1頁
Go語言單元測試模擬服務(wù)請求和接口返回_第2頁
Go語言單元測試模擬服務(wù)請求和接口返回_第3頁
Go語言單元測試模擬服務(wù)請求和接口返回_第4頁
Go語言單元測試模擬服務(wù)請求和接口返回_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論