Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pointers 使用指针接收器方法创建包装现有类型的接口_Pointers_Go_Interface - Fatal编程技术网

Pointers 使用指针接收器方法创建包装现有类型的接口

Pointers 使用指针接收器方法创建包装现有类型的接口,pointers,go,interface,Pointers,Go,Interface,我需要测试一个使用谷歌云Pubsub的应用程序,因此必须包装其类型Pubsub.Client和Pubsub.Subscriber,以便进行测试。然而,尽管进行了多次尝试,我还是无法获得一个可编译的接口 我试图包装的方法的定义如下: func (s *Subscription) Receive( ctx context.Context, f func(context.Context, *Message)) error func (c *Client) Subscription(id st

我需要测试一个使用谷歌云Pubsub的应用程序,因此必须包装其类型
Pubsub.Client
Pubsub.Subscriber
,以便进行测试。然而,尽管进行了多次尝试,我还是无法获得一个可编译的接口

我试图包装的方法的定义如下:

func (s *Subscription) Receive(
    ctx context.Context, f func(context.Context, *Message)) error

func (c *Client) Subscription(id string) *Subscription
这是当前的代码。
Receiver
接口(包装
Subscriber
)似乎可以工作,但我怀疑它可能需要更改才能修复
SubscriptionMaker
,因此我将两者都包括在内

注意:我已经尝试了几种引用和取消引用指针的变体,所以请不要告诉我更改,除非您解释了为什么建议的配置是正确的,或者您亲自验证了它是否编译

导入(
“上下文”
“cloud.google.com/go/pubsub”
)
类型接收机接口{
接收(context.context,func(ctx context.context,msg*pubsub.Message))(错误)
}
//Pubsub订阅实现接收器
var_u接收器=&pubsub.Subscription{}
类型SubscriptionMaker接口{
订阅(名称字符串)(s接收方)
}
//Pubsub客户端实现SubscriptionMaker
var_uusubscriptionMaker=pubsub.Client{}
当前错误消息:

common_types.go:21:5: cannot use "cloud.google.com/go/pubsub".Client literal (type "cloud.google.com/go/pubsub".Client) as type SubscriptionMaker in assignment:
    "cloud.google.com/go/pubsub".Client does not implement SubscriptionMaker (wrong type for Subscription method)
        have Subscription(string) *"cloud.google.com/go/pubsub".Subscription
        want Subscription(string) Receiver
这是办不到的


在接口上定义方法的类型签名时,它必须完全匹配
func(c*客户端)订阅(id字符串)*订阅
返回一个
*订阅
*订阅
是一个有效的
接收者
,但它不被视为符合接口方法
订阅(字符串)接收者
。Go需要精确匹配函数签名,而不是它通常用于接口的duck类型。

首先,对于大多数使用,使用包可能是测试pubsub更容易的方法。当然,您的特定问题可以应用于任何库,下面的方法对许多事情都很有用,而不仅仅是模仿
pubsub


您更广泛的目标是使用接口来模拟这样的库,这是可行的。但是,当您希望模拟的库返回无法模拟的具体类型时(可能是由于未报告的字段),情况就复杂了。所采用的方法比通常值得采用的方法复杂得多,因为可能有更简单的方法来测试代码

但是如果您打算这样做,那么您必须采取的方法是不要将整个包包装在接口中,而不仅仅是您希望模拟的特定方法中

您将需要包装您希望模拟的任何类型,这些类型也是由您的接口返回或接受的。这通常意味着您还需要修改生产代码(不仅仅是测试代码),因此这有时可能会破坏现有代码库的交易

我以前通常在模拟标准库的sql驱动程序时这样做,但这里也可以应用相同的方法。本质上,您需要为
pubsub
库创建一个包装包,甚至在生产代码中也要使用它。同样,这可能会对现有的代码库造成相当大的干扰,但为了说明起见。使用定义的接口:

package mypubsub

import "cloud.google.com/go/pubsub"

type Receiver interface {
    Recieve(context.Context, func(context.Context, *pubsub.Message) error)
}

type SubscriptionMaker interface {
    Subscription(string) Receiver
}
然后,您可以包装默认实现,以便在生产代码中使用:

// defaultClient wraps the default pubsub Client functionality.
type defaultClient struct {
    *pubsub.Client
}

func (d defaultImplementation) Subscription(name string) Receiver {
    return d.Client.Subscription()
}
当然,您需要扩展这个包来包装您正在使用的大部分或全部
pubsub
包。这可能有点令人畏惧


但是一旦你完成了,那么在你的代码中的任何地方使用你的
mypubsub
包,而不是直接依赖
pubsub
包。现在,您可以轻松地在任何需要测试的地方交换模拟实现。

定义了
Subscription
函数以返回
*Subscription
,但在您的界面中它返回
Receiver
。类型必须相同。
*Subscription
实现
Receiver
接口并不重要。类型必须完全匹配。因此不可能做到这一点,那么?如果您在界面中定义
Subscription
以返回
*pubiub.Subscription
,它将起作用。这无法实现使其在测试中可模拟的目标。所以这是不可能的。您可以实现这一点,但它需要使用自定义定义的类型来包装所有返回的类型。因此,您必须创建一个新类型来包装
*pubsub.Subscription
,并在整个应用程序中使用它,甚至为您的非测试代码创建一个自定义包装器。是的,这是一个很大的痛苦。这通常是不值得的。