lundi 9 février 2015

Interface use in golang for mocking third party libraries

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"


"http://ift.tt/192Vgm6"
"http://ift.tt/1DUH7B4"
)


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.


Aucun commentaire:

Enregistrer un commentaire