Правильне іменування пакетів для тестування з мовою Go


102

Я бачив кілька різних стратегій іменування тестових пакетів в 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до моїх пакетів тестування, оскільки це означає, що я не можу протестувати свої приватні методи пакету, але, можливо, є прихована перевага, про яку я не знаю?


9
Це питання призведе лише до різних думок, але я кину свою. Вам не потрібно перевіряти свої приватні методи. Ви хочете протестувати інтерфейс вашого пакету, який використовуватимуть інші розробники. Якщо тести не вдаються, тоді ви знаєте, що ваші приватні методи потребують перегляду.
Brenden

2
Приклад [дроту] ( github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go ) для Стратегії 2, насправді тепер є також прикладом Стратегії 1 ...
durp

Відповіді:


130

Принципова різниця між трьома перерахованими вами стратегіями полягає в тому, чи є тестовий код в тому ж пакеті, що і тестований код. Рішення про використання package myfuncабо package myfunc_testв тестовому файлі залежить від того, чи хочете ви виконати тестування білого або чорного ящиків .

У використанні обох методів у проекті немає нічого поганого. Наприклад, ви могли б мати myfunc_whitebox_test.goі myfunx_blackbox_test.go.

Порівняння пакетів тестових кодів

  • Тестування чорної скриньки: Використовуйте package myfunc_test, що забезпечить використання лише експортованих ідентифікаторів .
  • Тестування білої скриньки: Використовуйте для package myfuncтого, щоб мати доступ до не експортованих ідентифікаторів. Підходить для модульних тестів, які вимагають доступу до не експортованих змінних, функцій та методів.

Порівняння стратегій, перелічених у питанні

  • Стратегія 1: Файл myfunc_test.goвикористовує package myfunc- У цьому випадку тест - код в myfunc_test.goзнаходитиметься в тому ж пакеті, що і код тестованого в myfunc.go, що myfuncв цьому прикладі.
  • Стратегія 2: Файл myfunc_test.goвикористовує package myfunc_test- у цьому випадку тестовий код у myfunc_test.go"буде скомпільований як окремий пакет, а потім зв'язаний і запущений з основним тестовим двійковим файлом". [Джерело: Рядки 58–59 у вихідному коді test.go ]
  • Стратегія 3: файл myfunc_test.goвикористовує, package myfunc_testале імпортує, myfuncвикористовуючи позначення крапками - це варіант Стратегії 2, але використовує позначення крапками для імпорту myfunc.

1
Слід зазначити, що використання стратегії 1 також зберігатиме файли _test.goокремо, ніж тестований пакет (така сама поведінка, як стратегія 2). Здається, це не задокументовано на github.com/golang/go/issues/15315
Кевін Дінонаут

Я бачив сильний пакет, який використовує Strategy 3, але я не можу зрозуміти, в чому сенс?
PickBoy

1
Я розгалужив пакет і вніс зміни, і тепер усі мої тести намагаються імпортувати оригінальний репо замість мого розгалуженого пакета. У стратегії 3 мені не потрібно змінювати "github.com/original/link" на "github.com/my/fork", оскільки це просто посилання на '.' замість цього.
nmarley

1
@KevinDeenanauth Це мене просто здивувало. Я думав, що знайшов підводну камеру, коли щойно знайшов а _test.goз не- _testпакунковою назвою, що містить func init()яку змінює глобальну змінну пакета для тестування. Я був неправий.
Зіл

1
@nmarley .не вирішує проблему з форком. Це не відносний імпорт. Це лише імпортує ідентифікатори "в поточний пакет".
qaisjp

19

Це залежить від обсягу ваших тестів. Тести високого рівня (інтеграція, прийняття тощо ...), можливо, слід помістити в окремий пакет, щоб переконатися, що ви використовуєте пакет через експортований API.

Якщо у вас є великий пакет з великою кількістю внутрішніх органів, які потрібно перевірити, використовуйте той самий пакет для своїх тестів. Але це не запрошення для ваших тестів отримати доступ до будь-якої частини приватного стану. Це зробило б рефакторинг кошмаром. Коли я пишу структури в go, я часто впроваджую інтерфейси. Це ті методи інтерфейсу, які я використовую у своїх тестах, а не всі допоміжні методи / функції окремо.


13

Вам слід використовувати стратегію 1, коли це можливо. Ви можете використовувати спеціальну foo_testназву пакета, щоб уникнути циклів імпорту, але це в основному є, тому стандартну бібліотеку можна протестувати за допомогою того ж механізму. Наприклад, stringsне можна перевірити за допомогою стратегії 1, оскільки testingпакет залежить від strings. Як ви вже сказали, у стратегії 2 або 3 у вас немає доступу до приватних ідентифікаторів пакету, тому зазвичай краще не використовувати його, якщо вам не потрібно.


10
Як відсутність доступу до приватних ідентифікаторів у тестах не є гідністю?
jub0bs

3
відповідно до належної практики тестування, ви не тестуєте внутрішні деталі реалізації для артефакту коду; робить сина, запах коду
Gerardo Lima

0

Одні важливі примітки, про які я хотів би додати import .з Golang CodeReviewComments :

The import .Форма може бути корисна в тестах , які, з - за кругові залежності, не можуть бути зроблені частиною пакета тестуються:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

У цьому випадку тестовий файл не може бути у пакунку foo, оскільки він використовує bar/testutil, що імпортує foo. Тому ми використовуємо "імпорт". форма, щоб файл міг видавати себе частиною пакета foo, навіть якщо це не так.

За винятком цього випадку, не використовуйтеimport . у своїх програмах. Це значно ускладнює читання програм, оскільки незрозуміло, чи є ім’я на кшталт Quux ідентифікатором верхнього рівня в поточному пакеті чи в імпортованому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.