在Golang中,用于模拟第三方库的接口使用方法

huangapple go评论80阅读模式
英文:

Interface use in golang for mocking third party libraries

问题

我正在尝试使用VMware vSphere API客户端(govmomi)创建一个简单的模拟来对一些代码进行单元测试,但是我在寻找可用模式方面遇到了困难。

客户端库的一个简单用例是检索vSphere集群的安装许可证:

vclient, err := govmomi.NewClient(*vcurl, true)
if err != nil {
 return err
}
lic, err := vclient.LicenseManager().ListLicenses()

NewClient() 返回一个指向 Client 结构的指针,Client.LicenseManager() 返回一个 LicenseManager 结构的实例,LicenseManager.ListLicenses() 返回一个包含许可证信息的结构切片。作为一个有Python背景的人,我通常会对 LicenseManager 上的 ListLicenses() 方法进行模拟,但是我似乎无法找到Go中的可比模式或方法。

到目前为止,我尝试创建一个包含govmomi Client 结构作为匿名成员的包装结构 VCenterClient,以及一个用于创建具有模拟逻辑的包装结构新实例的“构造函数” NewVCenter()

import (
 "net/url"


 "github.com/vmware/govmomi"
 "github.com/vmware/govmomi/vim25/types"
)


type VCenterClient struct {
 VCenterClientInterface
}


type VCenterClientInterface interface {
 LicenseManager() LicenseManager
}


type LicenseManager interface {
 ListLicenses() ([]types.LicenseManagerLicenseInfo, error)
}


type VCenterClientMock struct{}
type LicenseManagerMock struct{}


func (v *VCenterClientMock) LicenseManager() LicenseManager {
 return LicenseManagerMock{}
}


func (l LicenseManagerMock) ListLicenses() ([]types.LicenseManagerLicenseInfo, error) {
 return make([]types.LicenseManagerLicenseInfo, 0), nil
}


func NewVCenterClient(uri string, mock bool) *VCenterClient {
 if mock {
 return &VCenterClient{&VCenterClientMock{}}
 }


 vcurl, _ := url.Parse(uri)
 vclient, _ := govmomi.NewClient(*vcurl, true)
 return &VCenterClient{vclient}
}

...但是我在使用接口来正确抽象govmomi库中的嵌套结构方面遇到了困难。我知道上述代码不起作用,因为 govmomi.LicenseManager() 返回类型为 govmomi.LicenseManager 的结构,而我的 VCenterClientInterface.LicenseManager() 方法返回类型为 LicenseManager 的接口。然而,我在寻找替代方案方面遇到了困难。

如果能在这种情况下提供更好的设计模式或正确使用接口的帮助,将不胜感激。

英文:

I'm trying to create a simple mock for unit testing some code using the VMware vSphere API client - govmomi - but I'm having trouble finding a usable pattern.

A simple use case for the client library would be to retrieve the installed licenses for a vSphere cluster:

vclient, err := govmomi.NewClient(*vcurl, true)
if err != nil {
 return err
}
lic, err := vclient.LicenseManager().ListLicenses()

NewClient() returns a pointer to a Client structure, Client.LicenseManager() returns an instance of a LicenseManager structure, and LicenseManager.ListLicenses() returns a slice of structures containing the license info. Coming from a Python background, I'd usually monkey patch the ListLicenses() method on LicenseManger for a mock, but I can't seem to come up with a comparable pattern or methodology in Go.

To this point, I've tried creating a wrapper structure VCenterClient with the govmomi Client structure as an anonymous member and a "constructor" function NewVCenter() to create new instances of the wrapper structure with logic for mocks:

import (
 "net/url"


 "github.com/vmware/govmomi"
 "github.com/vmware/govmomi/vim25/types"
)


type VCenterClient struct {
 VCenterClientInterface
}


type VCenterClientInterface interface {
 LicenseManager() LicenseManager
}


type LicenseManager interface {
 ListLicenses() ([]types.LicenseManagerLicenseInfo, error)
}


type VCenterClientMock struct{}
type LicenseManagerMock struct{}


func (v *VCenterClientMock) LicenseManager() LicenseManager {
 return LicenseManagerMock{}
}


func (l LicenseManagerMock) ListLicenses() ([]types.LicenseManagerLicenseInfo, error) {
 return make([]types.LicenseManagerLicenseInfo, 0), nil
}


func NewVCenterClient(uri string, mock bool) *VCenterClient {
 if mock {
 return &VCenterClient{&VCenterClientMock{}}
 }


 vcurl, _ := url.Parse(uri)
 vclient, _ := govmomi.NewClient(*vcurl, true)
 return &VCenterClient{vclient}
}

...but I having trouble using interfaces to properly abstract the nested structures in the govmomi library. I know the above will not work as govmomi.LicenseManager() returns a structure of type govmomi.LicenseManager and my VCenterClientInterface.LicenseManager() method returns an interface of type LicenseManager. However, I'm struggling to find an alternative.

Any help on a better design pattern or proper use of interfaces in this case would be much appreciated.

答案1

得分: 2

这个库是一个SOAP客户端(http://godoc.org/github.com/vmware/govmomi/vim25/soap#Client)。在HTTP层面上使用net/http/httptest(http://golang.org/pkg/net/http/httptest/)进行抽象,或者使用自己的HTTPRoundtripper来模拟响应。

英文:

This library is a SOAP client (http://godoc.org/github.com/vmware/govmomi/vim25/soap#Client). Abstract at the HTTP layer with net/http/httptest (http://golang.org/pkg/net/http/httptest/) or by using your own HTTPRoundtripper to mock the response.

huangapple
  • 本文由 发表于 2015年2月10日 04:11:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/28418430.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定