dep注入的模拟接口返回类型

问题描述

编辑

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

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

原帖

我是依赖项注入的新手,想在使用 couchbase go sdk 的模块上对其进行测试。为此,我需要接口来重现 ClusterBucket 结构。

在 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 方法需要返回一个实现 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 都会返回以下错误

linter error 1

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

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

这又给了我以下 lint 错误

linter error 2

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

解决方法

我认为您缺少的关键概念是模拟对象必须与您模拟的对象的接口要求相匹配。这包括方法的参数和返回值。

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

您仍然可以将 Database.Bucket 的返回值用作 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)
}