引入
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實現。