Создать интерфейс, оборачивающий существующие типы методами указателя-получателя - PullRequest
0 голосов
/ 19 июня 2019

Мне нужно протестировать приложение, которое использует Google Cloud 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 может потребоваться изменить его, поэтому я включил оба.

Примечание: я имеюпробовал несколько вариантов, где указывать и разыменовывать указатели, поэтому, пожалуйста, не просите меня изменить это, если у вас нет объяснения, почему ваша предложенная конфигурация является правильной, или вы лично убедились, что она компилируется.

import (
    "context"

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

type Receiver interface {
    Receive(context.Context, func(ctx context.Context, msg *pubsub.Message)) (err error)
}

// Pubsub subscriptions implement Receiver
var _ Receiver = &pubsub.Subscription{}

type SubscriptionMaker interface {
    Subscription(name string) (s Receiver)
}

// Pubsub clients implement SubscriptionMaker
var _ SubscriptionMaker = 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

Ответы [ 2 ]

0 голосов
/ 19 июня 2019

Во-первых, для большинства случаев использование пакета ptest, вероятно, гораздо более простой подход для тестирования 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.И теперь вы можете легко сменить фиктивную реализацию там, где вам нужно для тестирования.

0 голосов
/ 19 июня 2019

Этого нельзя сделать.

При определении сигнатуры типа метода на интерфейсе он должен точно совпадать.func (c *Client) Subscription(id string) *Subscription возвращает *Subscription, а *Subscription является допустимым Receiver, но оно не считается соответствующим интерфейсу Subscription(string) Receiver.Go требует точного соответствия для сигнатур функций, а не стиля утки, который он обычно использует для интерфейсов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...