Я видел несколько различных стратегий именования тестовых пакетов в Go и хотел узнать, каковы преимущества и недостатки каждой из них и какую из них мне следует использовать.
Стратегия 1:
Имя файла: github.com/user/myfunc.go
package myfunc
Имя тестового файла: github.com/user/myfunc_test.go
package myfunc
См. Пример bzip2 .
Стратегия 2:
Имя файла: github.com/user/myfunc.go
package myfunc
Имя тестового файла: github.com/user/myfunc_test.go
package myfunc_test
import (
"github.com/user/myfunc"
)
См. Пример провода .
Стратегия 3:
Имя файла: github.com/user/myfunc.go
package myfunc
Имя тестового файла: github.com/user/myfunc_test.go
package myfunc_test
import (
. "myfunc"
)
См. Пример строк .
Стандартная библиотека Go, похоже, использует комбинацию стратегии 1 и 2. Какую из всех трех мне следует использовать? Добавление package *_test
к моим тестовым пакетам проблематично, поскольку это означает, что я не могу тестировать частные методы своего пакета, но, может быть, есть скрытое преимущество, о котором я не знаю?
источник
Ответы:
Фундаментальное различие между тремя перечисленными стратегиями заключается в том, находится ли тестовый код в том же пакете, что и тестируемый код. Решение использовать
package myfunc
илиpackage myfunc_test
в тестовом файле зависит от того, хотите ли вы выполнить белый ящик или черный ящик тестирование .Нет ничего плохого в использовании обоих методов в проекте. Например, у вас может быть
myfunc_whitebox_test.go
иmyfunx_blackbox_test.go
.Сравнение пакетов тестового кода
package myfunc_test
, чтобы убедиться, что вы используете только экспортированные идентификаторы .package myfunc
чтобы у вас был доступ к неэкспортируемым идентификаторам. Подходит для модульных тестов, требующих доступа к неэкспортируемым переменным, функциям и методам.Сравнение рассматриваемых стратегий
myfunc_test.go
используетpackage myfunc
- В этом случае тест - код вmyfunc_test.go
будет находиться в том же пакете, что и код тестируемого вmyfunc.go
, чтоmyfunc
в этом примере.myfunc_test.go
используетpackage myfunc_test
- в этом случае тестовый код вmyfunc_test.go
«будет скомпилирован как отдельный пакет, а затем скомпонован и запущен с основным тестовым двоичным кодом ». [Источник: строки 58–59 в исходном коде test.go ]myfunc_test.go
использует,package myfunc_test
но импортирует,myfunc
используя точечную нотацию - это вариант стратегии 2, но для импорта используется точечная нотацияmyfunc
.источник
_test.go
отдельно от тестируемого пакета (такое же поведение, как и в стратегии 2). Похоже, это не задокументировано согласно github.com/golang/go/issues/15315_test.go
с_test
именем, отличным от пакета, содержащим a,func init()
который изменяет некоторую глобальную переменную пакета для тестирования. Я ошибался..
не решает проблему с вилкой. Это не относительное значение. Он просто импортирует идентификаторы «в текущий пакет».Это зависит от объема ваших тестов. Тесты высокого уровня (интеграция, приемка и т. Д.), Вероятно, следует поместить в отдельный пакет, чтобы убедиться, что вы используете пакет через экспортированный API.
Если у вас большой пакет с множеством внутренних компонентов, которые необходимо протестировать, используйте тот же пакет для своих тестов. Но это не приглашение вашим тестам получить доступ к какому-либо частному состоянию. Это превратило бы рефакторинг в кошмар. Когда я пишу структуры на ходу, я часто реализую интерфейсы. Это те методы интерфейса, которые я вызываю из своих тестов, а не все вспомогательные методы / функции по отдельности.
источник
По возможности следует использовать стратегию 1. Вы можете использовать специальное
foo_test
имя пакета, чтобы избежать циклов импорта, но в основном оно есть, поэтому стандартную библиотеку можно протестировать с помощью того же механизма. Например,strings
нельзя протестировать со стратегией 1, посколькуtesting
пакет зависит отstrings
. Как вы сказали, со стратегией 2 или 3 у вас нет доступа к частным идентификаторам пакета, поэтому обычно лучше не использовать его, если вам не нужно.источник
Одно важное замечание, которое я хотел бы добавить
import .
из Golang CodeReviewComments :import .
Форма может быть полезна в тестах , которые, из - за круговые зависимости, не могут быть сделаны частью пакета тестируются:В этом случае тестовый файл не может быть в пакете foo, потому что он использует
bar/testutil
, который импортирует foo. Итак, мы используем «импорт». форма, позволяющая файлу притворяться частью пакета foo, даже если это не так.За исключением этого случая, не используйте
import .
в своих программах. Это значительно затрудняет чтение программ, поскольку неясно, является ли такое имя, как Quux, идентификатором верхнего уровня в текущем пакете или в импортированном пакете.источник