dep 注入的模拟接口 return 类型

Mock interface return type for dep injection

编辑

正如接受的答案中所指出的,这里的问题是 go duck 打字方向错误。我想添加以下 github 问题作为附件,因为除了下面的 @matt 回答之外,它还为我提供了有用的信息:

https://github.com/golang/mock/issues/316#issuecomment-512043925

原版POST

我是依赖注入的新手,想在使用 couchbase go sdk. For this purpose I need interfaces to reproduce both Cluster and Bucket 结构的模块上测试它。

在 Cluster 接口上,我需要 Bucket() 方法,它具有以下签名:

func (c *gocb.Cluster) Bucket(bucketName string) *gocb.Bucket

我还需要 Bucket 接口中的以下两个方法:

func (b *gocb.Bucket) Collection(collectionName string) gocb.*Collection
func (b *gocb.Bucket) DefaultCollection() *gocb.Collection

棘手的部分是 Cluster 和 Bucket 方法都有指针接收器。这本身并不难,因为我知道如何单独模拟这些方法(您只需要使用指向实现接口的类型的指针)。

问题是其中一个 Cluster 方法需要 return 一个实现 Bucket 接口的指针,因为它也有指针接收器方法。我尝试了很多组合,但每次我使用非模拟 *gocb.Cluster 值作为我的一个函数的参数时,它都会失败,因为集群实例上的 Bucket 方法没有正确实现实例.

以下是我最近的尝试:

package deps

import (
    "github.com/couchbase/gocb/v2"
)

// Database mocks the gocb.Cluster interface.
type Database interface {
    Bucket(bucketName string) *Bucket
}

// Bucket mocks the gocb.Bucket interface.
type Bucket interface {
    Collection(collectionName string) *gocb.Collection
    DefaultCollection() *gocb.Collection
}

每当我尝试使用实际的 gocb.Cluster 值时,linter return 就会出现以下错误:

我还尝试将我的数据库接口中的 Bucket 方法签名替换为:

// Database mocks the gocb.Cluster interface.
type Database interface {
    Bucket(bucketName string) Bucket
}

这又给我以下 lint 错误:

如何实现一个接口来模拟这两种方法?

我认为您缺少的关键概念是模拟对象必须符合您所模拟对象的接口要求。这包括方法的参数和 return 值。

type Database interface {
    // Bucket(bucketName string) *Bucket   // Wrong
    Bucket(bucketName string) *gocb.Bucket // Correct
}

您仍然可以将 Database.Bucket 的 return 值用作 deps.Bucket,前提是您还正确地模拟了该接口。

除非我遗漏了有关您的测试过程的某些信息,否则这应该可以满足您的需要。

package main

import (
    "github.com/couchbase/gocb/v2"
)

// Database mocks the gocb.Cluster interface.
type Database interface {
    Bucket(bucketName string) *gocb.Bucket
}

// Bucket mocks the gocb.Bucket interface.
type Bucket interface {
    Collection(collectionName string) *gocb.Collection
    DefaultCollection() *gocb.Collection
}

func someFunc(db Database) *gocb.Bucket {
    return db.Bucket("")
}

func anotherFunc(bucket Bucket) {
    bucket.Collection("")
}

func main() {
    var cluster *gocb.Cluster
    bucket := someFunc(cluster)
    anotherFunc(bucket)
}