我正在使用第三方库,该库没有任何类的接口。我可以在我的结构中使用它们没问题,但它们有副作用,我想在单元测试时避免。
// Somewhere there are a couple structs, with no interfaces. I don't own the code.
// Each has only one method.
type ThirdPartyEntry struct {}
func (e ThirdPartyEntry) Resolve() string {
// Do some complex stuff with side effects
return "I'm me!"
}
// This struct returns an instance of the other one.
type ThirdPartyFetcher struct {}
func (f ThirdPartyFetcher) FetchEntry() ThirdPartyEntry {
// Do some complex stuff with side effects and return an entry
return ThirdPartyEntry{}
}
// Now my code.
type AwesomeThing interface {
BeAwesome() string
}
// I have a class that makes use of the third party.
type Awesome struct {
F ThirdPartyFetcher
}
func (a Awesome) BeAwesome() string {
return strings.Repeat(a.F.FetchEntry().Resolve(), 3)
}
func NewAwesome(fetcher ThirdPartyFetcher) Awesome {
return Awesome{
F: fetcher,
}
}
func main() {
myAwesome := NewAwesome(ThirdPartyFetcher{})
log.Println(myAwesome.BeAwesome())
}
这个有效!但是我想写一些单元测试,所以我想模仿第三方结构。为此,我相信我需要接口,但由于ThirdPartyFetcher返回ThirdPartyEntrys,我无法弄清楚如何。
我创建了一对与两个第三方类匹配的接口。我想重写Awesome结构和方法以使用通用Fetcher接口。在我的测试中,我会调用NewAwesome()传递一个testFetcher,一个也实现接口的结构。
type Awesome struct {
F Fetcher
}
func NewAwesome(fetcher Fetcher) Awesome {
return Awesome{
Fetcher: fetcher,
}
}
type Entry interface {
Resolve() string
}
// Double check ThirdPartyEntry implements Entry
var _ Entry = (*ThirdPartyEntry)(nil)
type Fetcher interface {
FetchEntry() Entry
}
// Double check ThirdPartyFetcher implements Fetcher
var _ Fetcher = (*ThirdPartyFetcher)(nil)
我省略了测试代码,因为它不相关。这在显示的最后一行失败。
./main.go:49: cannot use (*ThirdPartyFetcher)(nil) (type *ThirdPartyFetcher) as type Fetcher in assignment:
*ThirdPartyFetcher does not implement Fetcher (wrong type for FetchEntry method)
have FetchEntry() ThirdPartyEntry
want FetchEntry() Entry
签名是不同的,即使我已经表明ThirdPartyEntry实现了Entry。我相信这是不允许的,因为会导致像切片这样的东西(在多态意义上,而不是golang意义上)。我有什么方法可以编写一对接口吗?应该是Awesome类甚至不知道ThirdParty存在的情况 - 它在接口后面被抽象并在main调用NewAwesome时被注入。
答案 0 :(得分:2)
它不是很漂亮,但有一种方法是:
type fetcherWrapper struct {
ThirdPartyFetcher
}
func (fw fetcherWrapper) FetchEntry() Entry {
return fw.ThirdPartyFetcher.FetchEntry()
}
我说嘲笑返回结构与接口的东西是一个相对常见的问题,除了大量的中间包装之外没有任何好的解决方案。