在golang中实现嵌套接口

AKn*_*nox 1 unit-testing interface go

我有一个接口,有很多子方法.

type InterfaceCheckout interface {
    GetID()    int
    GetItems() []InterfaceCartItem
    // ... then like 30more methods
}
Run Code Online (Sandbox Code Playgroud)

我有一个只使用GetItems方法的方法.

func GetRates(checkoutI InterfaceCheckout) []Rate {
    for _, item := range checkoutI.GetItesm() {
        p := item.GetProduct()
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望能够在GetRates不模仿所有方法的情况下测试此方法InterfaceCheckout.

我以为我能够:

  1. 创建一些较小的接口,仅指定我正在使用的方法
  2. 将输入转换为此新界面
  3. 传递给一个新的内部方法

    func GetRates(checkoutI InterfaceCheckout) []Rate {
        getRates(checkoutWrapper(checkoutI))
    }
    
    func getRates(checkoutI checkoutWrapper) []Rate {
        for _, item := range checkoutI.GetItesm() {
            p := item.GetProduct()
        }
    }
    
    // smaller wrapper interfaces
    type checkoutWrapper interface {
        GetItems() []InterfaceCartItem
    }
    
    Run Code Online (Sandbox Code Playgroud)

我遇到的问题InterfaceCartItem是返回的GetItems有大约30个方法在接口中列出,我只使用其中一个GetProduct.所以我认为我可以使用相同的解决方案并使用我需要的一个方法创建一个接口,但是当我尝试更改从checkoutWrapper@GetItems()golang 返回的类型时说checkoutI不再满足checkoutWrapper接口,因为它返回一个GetItems技术上不同的类型真正...

我试过的代码不起作用

func GetRates(checkoutI InterfaceCheckout) []Rate {
    getRates(checkoutWrapper(checkoutI))
}

func getRates(checkoutI InterfaceCheckout) []Rate {
    for _, item := range checkoutI.GetItesm() {
        p := item.GetProduct()
    }
}

// smaller wrapper interfaces
type checkoutWrapper interface {
    GetItems() []itemWrapper
}

type itemWrapper interface {
    GetProduct() InterfaceProduct
}
Run Code Online (Sandbox Code Playgroud)

接口方法验证只做了一层深度吗?

cni*_*tar 6

只需将您的界面嵌入假对象中即可.例如:

type InterfaceCheckout interface {
    GetID() int
    GetItems() []InterfaceCartItem
}

type InterfaceCartItem interface {
    GetProduct() string
    GetID() int
}

type fakeCheckout struct {
    InterfaceCheckout
}

func (fakeCheckout) GetItems() []InterfaceCartItem {
    return []InterfaceCartItem{fakeItem{}}
}

type fakeItem struct {
    InterfaceCartItem
}

func (fakeItem) GetProduct() string {
    return "This is the end"
}

func getRates(checkoutI InterfaceCheckout) {
    for _, item := range checkoutI.GetItems() {
        fmt.Printf("%v\n", item.GetProduct())
    }
}

func main() {
    fc := fakeCheckout{}
    getRates(fc)
}
Run Code Online (Sandbox Code Playgroud)

请参阅以下网址:https://play.golang.org/p/uSFegnZq7S


旁注:避免使用30种方法的接口,它们会非常快速地变得非常麻烦.


编辑

这有效,但可以解释为什么在结构中嵌入接口有效

界面嵌入在结构中有点微妙.规范提到嵌入一个接口会带来它的方法集,因此当你调用它总是编译的方法时.它还引入了接口类型的nil成员.

typ := reflect.TypeOf(fc)
fmt.Printf("+%v\n", typ.Field(0))
Run Code Online (Sandbox Code Playgroud)

你可以看到那里有一个成员:

{Name:InterfaceCheckout PkgPath: Type:main.InterfaceCheckout Tag: Offset:0 Index:[0] Anonymous:true}
Run Code Online (Sandbox Code Playgroud)

它在运行时如何工作?

  • 当你调用一个你的类型重写1的方法时,一切都很好:你的方法被调用
  • 当您调用不覆盖的方法时,调用将进入嵌入对象,该对象为nil.这有点像下面的恐慌:

    var ic InterfaceCheckout // nil, just like your embedded type
    ic.GetItems()
    
    Run Code Online (Sandbox Code Playgroud)

1.类型可以自由地覆盖其嵌入类型带来的方法