unit-testing - 在 golang 中实现嵌套接口(interface)

标签 unit-testing go interface

我有一个包含很多子方法的接口(interface)。

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

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

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

我希望能够测试此 GetRates 方法,而无需模拟 InterfaceCheckout 中的所有方法。

我以为我能够:

  1. 创建一些更小的接口(interface),仅指定我正在使用的方法
  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
    }
    

我遇到的问题是 GetItems 返回的 InterfaceCartItem 在接口(interface)中列出了大约 30 种方法,而我只使用了其中一种 获取产品。所以我想我可以使用相同的解决方案并使用我需要的一种方法创建一个接口(interface),但是当我尝试更改从 checkoutWrapper@GetItems() 返回的类型时,golang 说 checkoutI 不再满足 checkoutWrapper 接口(interface),因为它返回与 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
}

那么接口(interface)方法验证是否只进行了一层深度?

最佳答案

只需将您的界面嵌入到假对象中。 例如:

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)
}

查看它的运行情况:https://play.golang.org/p/uSFegnZq7S


旁注:避免使用 30 个方法的接口(interface),它们很快就会变得非常麻烦。


编辑

This works, but could explain why embedding the interface in the struct works

在结构中嵌入接口(interface)有点微妙。 The spec提到嵌入接口(interface)会引入它的方法集,因此当你调用它总是编译的方法时。它还引入了接口(interface)类型的 nil 成员。

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

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

{Name:InterfaceCheckout PkgPath: Type:main.InterfaceCheckout Tag: Offset:0 Index:[0] Anonymous:true}

它在运行时如何工作?

  • 当您调用您的类型覆盖的方法时1 一切正常:您的方法被调用
  • 当您调用一个您未覆盖的方法时,该调用会传递到为 nil 的嵌入对象。这种 panic 很像以下内容:

    var ic InterfaceCheckout // nil, just like your embedded type
    ic.GetItems()
    

<子>1。类型可以自由覆盖其嵌入类型引入的方法

关于unit-testing - 在 golang 中实现嵌套接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37484935/

相关文章:

c# - 如何模拟/单元测试 HTTP 客户端 - restease

dll - 在我的 C# 解决方案中,解耦架构中的接口(interface)应存储在哪里?

go - 无法编码 json.decoded 请求正文

go - Golang Gorilla session 无法在Windows10上保存

go - 如何在查询中使用Firestore DocumentID __name__

if-statement - Golang 新手,如果 else 不工作,由于某种原因嵌套

java - 接口(interface)实现避免大类

unit-testing - 使用 angular 和 jasmine 进行测试时如何模拟浏览器焦点?

c# - Lambda 表达式作为 xUnit 中的内联数据

objective-c - 在测试中转换 NSRange 吗?