searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Gomonkey单元测试工具库

2023-09-20 09:40:10
46
0

引入

go get github.com/agiledragon/gomonkey/v2

gomoneky方法一览

// 函数打桩
func ApplyFunc(target, double interface{}) *Patches {}
// 方法打桩
func ApplyMethod(target reflect.Type, methodName string, double interface{}) *Patches {}
// 全局变量打桩
func ApplyGlobalVar(target, double interface{}) *Patches {}
// 函数变量打桩
func ApplyFuncVar(target, double interface{}) *Patches {}
// 函数序列打桩
func ApplyFuncSeq(target interface{}, outputs []OutputCell) *Patches {}
// 方法序列打桩
func ApplyMethodSeq(target reflect.Type, methodName string, outputs []OutputCell) *Patches {}
// 函数变量序列打桩
func ApplyFuncVarSeq(target interface{}, outputs []OutputCell) *Patches {}

打桩一个函数

这是我们使用较多的情况,举个栗子:

某openApi的http client,其初始化函数为:

// NewOpenApiClient 根据客户id生成相应的openapi client
func NewOpenApiClient(accountId string) (*client.EcxAPIGoClient, error) {
.................................
   openApiClient := client.New(rt, nil)
   return openApiClient, nil
}

gomonkey可以灵活的在单测中patch任何一个函数,这个函数可能是一个工具函数,对于它们我们早已经验证了其正确性,还是以上述NewOpenApiClient为例,我们只需要调用gomonkey的applyFunc方法来是的运行test.go文件时替换掉本函数即可,示例:

func Test(t *testing.T) {
   ctrl := gomock.NewController(t)
   defer ctrl.Finish()
   backendGroupClient := backend_group.NewMockClientService(ctrl)
   patches := gomonkey.ApplyFunc(openapi.NewOpenApiClient, func(accountId string) (goClient *client.EcxAPIGoClient, err error) {
      return &client.EcxAPIGoClient{
         BackendGroup: backendGroupClient,
      }, nil
   })
   defer patches.Reset()
}

 

打桩一个方法

gomonkey可以为一个对象方法打桩,还是以openApiClient为例,我们创建一个struct,让它实现newClient方法:

type client struct{}
 
 
func (c *client) NewOpenApiClient(accountId string) (*client.EcxAPIGoClient, error) {
......
}

测试方法:

func Test(t *testing.T) {
   var cli *cli
   patches := gomonkey.ApplyMethod(reflect.TypeOf(cli),"NewOpenApiClient", func (_ *cli, accountId string) (*client.EcxAPIGoClient, error) {
           return ....
   })
   defer patches.Reset()
}

 

打桩一个变量

var num = 10
 
func Test(t *testing.T){
    patches := gomonkey.ApplyGlobalVar(&num, 12)
    defer patches.Reset()
}

 

打桩一个函数返回序列

gomonkey可以模拟一个函数被请求多次的返回序列,不太恰当的,我们模拟请求上述newOpenApi函数的三次返回,分别返回三个不同的client:

func Test(t *testing.T) {
   outputs := []gomonkey.OutputCell{
      {Values: gomonkey.Params{client1, nil}}, // 第一次请求返回client1
      {Values: gomonkey.Params{client2, nil}}, // 第二次请求返回client2
      {Values: gomonkey.Params{client3, nil}}, // 第三次请求返回client3
   }
   patches := gomonkey.ApplyFuncSeq(openapi.NewOpsOpenApiClient, outputs)
   defer patches.Reset()
}

打桩方法序列则与打桩方法类似,首先需要声明方法所属对象的类型,指定打桩方法名,最后与函数返回序列一致,定义期望的多次返回即可。

特别地,经测试如果我们需要模拟一个函数或者方法被多次请求,但是每次返回一致,那么只需要patch该函数或者方法即可,不需要使用序列相关的方法。

一些限制

1.gomonkey极少数情况会因为内联的原因导致失效,解决方法:

go test -v -gcflags=-l

2.gomonkey提供的现有方法应该不能实现链式调用的打桩,例如k8sClient get node,所以按照之前的等待job结束方法单测,还是需要通过fake实现。

0条评论
0 / 1000
高****琦
2文章数
1粉丝数
高****琦
2 文章 | 1 粉丝
高****琦
2文章数
1粉丝数
高****琦
2 文章 | 1 粉丝
原创

Gomonkey单元测试工具库

2023-09-20 09:40:10
46
0

引入

go get github.com/agiledragon/gomonkey/v2

gomoneky方法一览

// 函数打桩
func ApplyFunc(target, double interface{}) *Patches {}
// 方法打桩
func ApplyMethod(target reflect.Type, methodName string, double interface{}) *Patches {}
// 全局变量打桩
func ApplyGlobalVar(target, double interface{}) *Patches {}
// 函数变量打桩
func ApplyFuncVar(target, double interface{}) *Patches {}
// 函数序列打桩
func ApplyFuncSeq(target interface{}, outputs []OutputCell) *Patches {}
// 方法序列打桩
func ApplyMethodSeq(target reflect.Type, methodName string, outputs []OutputCell) *Patches {}
// 函数变量序列打桩
func ApplyFuncVarSeq(target interface{}, outputs []OutputCell) *Patches {}

打桩一个函数

这是我们使用较多的情况,举个栗子:

某openApi的http client,其初始化函数为:

// NewOpenApiClient 根据客户id生成相应的openapi client
func NewOpenApiClient(accountId string) (*client.EcxAPIGoClient, error) {
.................................
   openApiClient := client.New(rt, nil)
   return openApiClient, nil
}

gomonkey可以灵活的在单测中patch任何一个函数,这个函数可能是一个工具函数,对于它们我们早已经验证了其正确性,还是以上述NewOpenApiClient为例,我们只需要调用gomonkey的applyFunc方法来是的运行test.go文件时替换掉本函数即可,示例:

func Test(t *testing.T) {
   ctrl := gomock.NewController(t)
   defer ctrl.Finish()
   backendGroupClient := backend_group.NewMockClientService(ctrl)
   patches := gomonkey.ApplyFunc(openapi.NewOpenApiClient, func(accountId string) (goClient *client.EcxAPIGoClient, err error) {
      return &client.EcxAPIGoClient{
         BackendGroup: backendGroupClient,
      }, nil
   })
   defer patches.Reset()
}

 

打桩一个方法

gomonkey可以为一个对象方法打桩,还是以openApiClient为例,我们创建一个struct,让它实现newClient方法:

type client struct{}
 
 
func (c *client) NewOpenApiClient(accountId string) (*client.EcxAPIGoClient, error) {
......
}

测试方法:

func Test(t *testing.T) {
   var cli *cli
   patches := gomonkey.ApplyMethod(reflect.TypeOf(cli),"NewOpenApiClient", func (_ *cli, accountId string) (*client.EcxAPIGoClient, error) {
           return ....
   })
   defer patches.Reset()
}

 

打桩一个变量

var num = 10
 
func Test(t *testing.T){
    patches := gomonkey.ApplyGlobalVar(&num, 12)
    defer patches.Reset()
}

 

打桩一个函数返回序列

gomonkey可以模拟一个函数被请求多次的返回序列,不太恰当的,我们模拟请求上述newOpenApi函数的三次返回,分别返回三个不同的client:

func Test(t *testing.T) {
   outputs := []gomonkey.OutputCell{
      {Values: gomonkey.Params{client1, nil}}, // 第一次请求返回client1
      {Values: gomonkey.Params{client2, nil}}, // 第二次请求返回client2
      {Values: gomonkey.Params{client3, nil}}, // 第三次请求返回client3
   }
   patches := gomonkey.ApplyFuncSeq(openapi.NewOpsOpenApiClient, outputs)
   defer patches.Reset()
}

打桩方法序列则与打桩方法类似,首先需要声明方法所属对象的类型,指定打桩方法名,最后与函数返回序列一致,定义期望的多次返回即可。

特别地,经测试如果我们需要模拟一个函数或者方法被多次请求,但是每次返回一致,那么只需要patch该函数或者方法即可,不需要使用序列相关的方法。

一些限制

1.gomonkey极少数情况会因为内联的原因导致失效,解决方法:

go test -v -gcflags=-l

2.gomonkey提供的现有方法应该不能实现链式调用的打桩,例如k8sClient get node,所以按照之前的等待job结束方法单测,还是需要通过fake实现。

文章来自个人专栏
GLQ
2 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0