Golang интерфейсы и насмешки - PullRequest
4 голосов
/ 11 марта 2019

Мне тяжело писать модульные тесты на Go из-за внешних библиотек, которые не предоставляют интерфейс (а значит, не являются поддельными), а только чистые функции. Даже большие, такие как Google не , поэтому мне интересно, достаточно ли хорош мой подход. Не будет ли хорошей практикой для библиотек предоставлять interface s вместо пакетов только с функциями, чтобы позволить пользователю издеваться над ними?

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

Я пришел с примером. Моя функция может выглядеть следующим образом

func AnyFunction() error {
    sess := session.Get("blabla")
    // logic in here...
}

, где сессия является импортированным пакетом, который возвращает struct. Я не могу издеваться над посылкой session. Для этого случая я напишу SessionInterface с реализацией, которая внутренне вызывает сессию.

Ex:

type SessionInterface interface {
    Get(s string) Session
}

type mySessionImpl struct {}
func (me *mySessionImpl) Get(s string) Session {
  return session.Get(s)
}

Теперь для моих тестов я могу смоделировать SessionInterface и вставить его в мой код

Ответы [ 2 ]

1 голос
/ 13 марта 2019

Вы все делаете правильно, и это было сознательное решение со стороны разработчиков языка.

Философия Go заключается в том, что ваш код должен «владеть» этими интерфейсами, а не библиотекой. В таких языках, как C # и Java, библиотеки заранее определяют свои интерфейсы, не зная, что на самом деле нужно потребителю. (Возможно, они включают в себя слишком много методов или слишком мало.) В Go, поскольку потребитель эффективно «владеет» интерфейсами, вы можете указать, какие методы действительно должны присутствовать в минимальном интерфейсе, и изменения требований вашей программы. означает, что вы также можете изменить интерфейс.

Теперь в этом конкретном случае может показаться странным создание адаптера перед функцией для тестируемости, но рассмотрим альтернативный вариант: если бы session.Get() был методом интерфейса или структуры, а не функцией, это вызвало бы все потребители библиотеки должны создать фиктивный объект для вызова метода. Не все собираются притворяться - им легче сказать, что потребители, которые хотят (как и вы), имеют право на написание адаптеров, а те, кто не может блаженно их игнорировать.

1 голос
/ 11 марта 2019

IMO - это супер распространенное решение, обеспечивающее хороший баланс между ремонтопригодностью и тестируемостью.

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

  • версия "prod", т.е. библиотека, которую вы тестируете
  • тестовая версия, заглушка, реализующая интерфейс

При таком подходе заглушка может проверять только вашу службу и границы ее зависимостей в соответствии с контрактом интерфейса, она очень мало или совсем ничего не гарантирует о совместном использовании / интеграции ваших компонентов с заглушаемой библиотекой. По моему опыту, этот подход работает потрясающе и является моим личным предпочтением. Я считаю, что важно иметь 1 или 2 высокоуровневых теста, обеспечивающих успешную инициализацию вашего компонента и взаимодействие с версией библиотеки «prod».


Штекер:

Я уже писал об этой проблеме https://medium.com/dm03514-tech-blog/you-are-going-to-need-it-using-interfaces-and-dependency-injection-to-future-proof-your-designs-2cf6f58db192

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