【问题标题】:How can I mock multiple types when the signature of a concrete method refers to another concrete type, not its interface?当具体方法的签名引用另一个具体类型而不是它的接口时,如何模拟多种类型?
【发布时间】:2016-02-14 12:29:21
【问题描述】:

我正在使用一个第三方库,它的类没有任何接口。我可以在我的结构中使用它们没问题,但是它们有我想在单元测试时避免的副作用。

// 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。我认为这是不允许的,因为 to 会导致切片(在多态意义上,而不是 golang 意义上)。有什么办法让我写一对接口吗?应该是 Awesome 类甚至不知道 ThirdParty 的存在——它在接口后面被抽象出来,并在 main 调用 NewAwesome 时注入。

【问题讨论】:

    标签: testing go mocking


    【解决方案1】:

    这不是很漂亮,但一种方法是:

    type fetcherWrapper struct {
        ThirdPartyFetcher
    }
    
    func (fw fetcherWrapper) FetchEntry() Entry {
        return fw.ThirdPartyFetcher.FetchEntry()
    }
    

    我想说,模拟返回结构与接口的东西是一个相对常见的问题,除了大量中间包装之外,没有任何好的解决方案。

    【讨论】:

    • 感谢@AlexGuerra。您也在确认我从其他一些来源听到的消息,这似乎是我测试的最佳选择。
    猜你喜欢
    • 2012-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多