Go语言单元测试模拟服务请求和接口返回_第1页
Go语言单元测试模拟服务请求和接口返回_第2页
Go语言单元测试模拟服务请求和接口返回_第3页
Go语言单元测试模拟服务请求和接口返回_第4页
Go语言单元测试模拟服务请求和接口返回_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第Go语言单元测试模拟服务请求和接口返回目录前言httptestgock安装使用示例总结

前言

这是Go单元测试从入门到放弃系列教程的第1篇,介绍了如何使用httptest和gock工具进行网络测试。

在上一篇《Go单元测试从入门到放弃0.单元测试基础》中,我们介绍了Go语言编写单元测试的基础内容。

而实际工作中的业务场景往往会比较复杂,无论我们的代码是作为server端对外提供服务或者还是我们依赖别人提供的网络服务(调用别人提供的API接口)的场景,我们通常都不想在测试过程中真正的建立网络连接。本文就专门介绍如何在上述两种场景下mock网络测试。

httptest

在Web开发场景下的单元测试,如果涉及到HTTP请求推荐大家使用Go标准库net/http/httptest进行测试,能够显著提高测试效率。

在这一小节,我们以常见的gin框架为例,演示如何为httpserver编写单元测试。

假设我们的业务逻辑是搭建一个httpserver端,对外提供HTTP服务。我们编写了一个helloHandler函数,用来处理用户请求。

//

gin.go

package

httptest_demo

import

(

"fmt"

"net/http"

"/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(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

现在我们需要为helloHandler函数编写单元测试,这种情况下我们就可以使用httptest这个工具mock一个HTTP请求和响应记录器,让我们的server端接收并处理我们mock的HTTP请求,同时使用响应记录器来记录server端返回的响应内容。

单元测试的示例代码如下:

//

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),

//

请求参数

//

mock一个响应记录器

w

:=

httptest.NewRecorder()

//

让server端处理mock请求并记录返回的响应内容

r.ServeHTTP(w,

req)

//

校验状态码是否符合预期

assert.Equal(t,

http.StatusOK,

w.Code)

//

解析并检验响应内容是否复合预期

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"])

执行单元测试,查看测试结果

❯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服务中为请求处理函数编写单元测试了。

gock

上面的示例介绍了如何在HTTPServer服务类场景下为请求处理函数编写单元测试,那么如果我们是在代码中请求外部API的场景(比如通过API调用其他服务获取返回值)又该怎么编写单元测试呢?

例如,我们有以下业务逻辑代码,依赖外部API:/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

:=

amp;ReqParam{X:

x}

b,

_

:=

json.Marshal(p)

//

调用其他服务的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返回的数据做一些逻辑处理

return

ret.Value

+

y

在对类似上述这类业务代码编写单元测试的时候,如果不想在测试过程中真正去发送请求或者依赖的外部接口还没有开发完成时,我们可以在单元测试中对依赖的API进行mock。

这里推荐使用gock这个库。

安装

go

get

-u

gopkg.in/h2non/gock.v1

使用示例

使用gock对外部API进行mock,即mock指定参数返回约定好的响应内容。下面的代码中mock了两组数据,组成了两个测试用例。

//

api_test.go

package

gock_demo

import

(

"testing"

"/stretchr/testify/assert"

"gopkg.in/h2non/gock.v1"

func

TestGetResultByAPI(t

*testing.T)

{

defer

gock.Off()

//

测试执行后刷新挂起的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})

//

调用我们的业务函数

res

:=

GetResultByAPI(1,

1)

//

校验返回结果是否符合预期

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})

//

调用我们的业务函数

res

=

GetResultByAPI(2,

2)

//

校验返回结果是否符合预期

assert.Equal(t,

res,

202)

assert.True(t,

gock.IsDone())

//

断言mock被触发

执行上面写好的单元测试,看一下测试结果。

❯gotest-v

===RUNTestGetResultByAPI

---PASS:TestGetResultByAPInbsp;(0.00s)

PASS

okgolang-unit-test-demo/gock_demo0.054s

测试结果和预期的完全一致。

在这个示例中,为了让大家能够清晰的了解gock的使用,我特意没有使用表格驱动测试。给大家留一个小作业:自己动手把这个单元测试改写成表格驱动测试的风

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论