我的问题并不复杂。首先,我将写一个简单的示例,然后在漏掉任何细微之处后再显示真实的代码。
所以我有一个第三方库:
// Third party library
type ThirdPartyFoo struct {}
func (t *ThirdPartyFoo) DoFoo () *ThirdPartyFoo {
println("I'm a third party library!")
return t
}
我想使用该库来调用DoFoo()
:
type MyThing struct {
TheFoo ThirdPartyFoo
}
func (myThing *MyThing) WhichLib () {
myThing.TheFoo.DoFoo()
}
我想用ThirdPartyFoo
的模拟版本进行测试,因为,我还应该如何验证DoFoo()
是A)调用的,B)使用正确的参数调用的,以及C) MyThing
根据不同的返回值正确响应吗?
我尝试使用MyThing
内部的接口,而不是直接依赖ThirdPartyFoo
...
type IThirdPartyFoo interface {
DoFoo() *IThirdPartyFoo
}
type MyThingWithI struct {
TheFoo IThirdPartyFoo
}
func (myThing *MyThingWithI) WhichLib () {
myThing.TheFoo.DoFoo()
}
然后调用该功能...
func main() {
realFoo := ThirdPartyFoo{}
realThing := MyThingWithI{
TheFoo: &realFoo,
}
realThing.WhichLib()
}
但是在运行时失败:
proxyutils/serviceregistrar.go:44:9: cannot use &realFoo (type *ThirdPartyFoo) as type IThirdPartyFoo in field value:
*ThirdPartyFoo does not implement IThirdPartyFoo (wrong type for DoFoo method)
have DoFoo() *ThirdPartyFoo
want DoFoo() IThirdPartyFoo
所以...我花了几个小时试图弄清楚这个问题,又花了一个小时写这篇文章...我仍然迷路了。我唯一能想到的解决方案是完全包装第三方库,如下所示:
type IThirdPartyFooWrapper interface {
DoFoo() IThirdPartyFooWrapper
}
type ThirdPartyFooWrapper struct {
IThirdPartyFooWrapper
ThirdPartyFoo ThirdPartyFoo
}
func (w *ThirdPartyFooWrapper) DoFoo () IThirdPartyFooWrapper {
w.ThirdPartyFoo.DoFoo()
return w
}
type MyThingWithI struct {
TheFooWrapper IThirdPartyFooWrapper
}
func (myThing *MyThingWithI) WhichLib() {
myThing.TheFooWrapper.DoFoo()
}
但是已经有很多间接级别了,我真的很讨厌添加这个级别。这就是嘲笑的目的,但是Go语言似乎已经完全解决了所有不幸的糟糕问题,以至于开始使用不使用接口的第三方库。
最后,这是我的真实代码。 *mux.Router
作为ServiceRegistrar
的一部分是有问题的。
package proxyutils
import (
"errors"
"github.com/gorilla/mux"
"net/http"
)
type IProxyRegistrar interface {
Register(input Registration) error
}
type ServiceRegistrarFactory struct{}
func (_ *ServiceRegistrarFactory) Build(proxyRegistrar IProxyRegistrar, router *mux.Router) (*ServiceRegistrar, error) {
if nil == proxyRegistrar {
return nil, errors.New("cannot create ServiceRegistrar with nil IProxyRegistrar")
}
if nil == router {
return nil, errors.New("cannot create ServiceRegistrar with nil mux.Router")
}
return &ServiceRegistrar{
proxyRegistrar: proxyRegistrar,
router: router,
}, nil
}
type ServiceRegistrar struct {
proxyRegistrar IProxyRegistrar
router *mux.Router
}
func (r *ServiceRegistrar) Register(userRegistration Registration, f func(http.ResponseWriter, *http.Request)) error {
err := r.proxyRegistrar.Register(userRegistration)
if nil == err {
var route *mux.Route
if userRegistration.PathIsPrefix {
route = r.router.PathPrefix(userRegistration.Path)
} else {
route = r.router.Path(userRegistration.Path)
}
route.Methods(userRegistration.Methods...).HandlerFunc(f)
return nil
} else {
return err
}
}