Проект, с которого я начал go-blueprint, имеет такие модули, как:
./cmd
./api
./main.go (main)
./internal
...
./server
...
./server.go (server -> app/internal/server)
...
...
./tests
./handler_test.go
(Конечно, внутри гораздо больше файлов и папок internal
.)
В настоящее время handler_test.go
тестируется ./internal/server/server.go
, и выполнение go test
запустит этот тест.
Я привык проводить тесты в зеркальной структуре папок, поэтому мне хотелось бы иметь
./internal
./server
./server.go
./tests
./server
./server_test.go
При этом я могу go test app/tests/server
и он работает server_test.go
, но другого теста нет.
Я попробовал использовать t.Run и хотел бы импортировать тестовые функции, однако это не работает:
// ./tests/server_test.go
package tests
import (
testServer "app/tests/server" // ❌ could not import app/tests/server (no required module provides package "app/tests/server")
"testing"
)
func TestServer(t *testing.T) {
t.Run("Testing server routes", testServer.TestBaseRoutes)
}
Возможно, я не понимаю парадигму, исходящую от JUnit, PHPUnit, Jest и т. д., но я, кажется, не понимаю, как Go структурирует тесты, когда используемое приложение имеет средний размер и, возможно, содержит десятки тестовых файлов.
Возможно ли вообще то, что я делаю?
«Я привык, что тесты размещаются в зеркальной структуре папок». Вам придется привыкнуть к другому способу размещения тестов. «Кажется, я не понимаю, как Go структурирует тесты» Go организован в виде пакетов. Код и тесты пакета находятся в одной папке. Вы не можете импортировать «тестовый код». Каждый пакет должен быть автономным, включая тесты.
@Volker, тогда почему go-blueprint
создает приложение с папкой tests
? Не является ли это заблуждением?
@JimB, тогда почему go-blueprint
создает приложение с папкой tests
? Не является ли это заблуждением?
@YanickRochon, вам придется спросить их или обратиться к документации, это не является требованием языкового инструментария. Я предполагаю, что это репозиторий для различных интеграционных тестов, которые не умещаются в одном пакете.
@JimB Я все еще не понимаю. Смотрите, если у меня есть файл в папке tests
, то go test
найдет его автоматически. Если у меня есть тесты вместе с файлами под internal
, то Go не найдет их, пока я не найду go test ./...
, но он также найдет другие файлы .go. Это крайне противоречиво.
go test
сам по себе ничего не находит, без идентификатора пакета он предполагает, что пакет находится в текущем рабочем каталоге, и аналогичен go test .
. Аргумент ./...
— это подстановочный знак, который включает пакеты в текущем рабочем каталоге и во всех подкаталогах.
«Если у меня есть файл в папке тестов, то go test найдет его автоматически» — это фактически неверное утверждение, которое не соответствует фактическому поведению go test
. «Если у меня есть тесты вместе с файлами во внутренней папке, то Go не найдет их, пока я не пройду тест ./...» снова фактическая ошибка. Внутренние пакеты не отличаются от любого другого пакета в отношении тестирования. Вы либо делаете go test
в пакете, либо go test full/package/import/path
. «Это крайне противоречиво» только потому, что ваши предположения о том, как работает тест go, не соответствуют фактическому поведению.
Просто отметим, что вам следует оформить заказ pkg.go.dev/github.com/stretchr/testify/suite package. Помог мне организовать тесты, аналогичные PHPUnit.
Тесты Go обычно живут в том же пакете , что и исходные файлы. Даже go-blueprint
недавно исправили свои шаблоны. Если вам нравятся более идиоматические шаблоны проектов, возможно, вам стоит взглянуть на gonew.
Смысл, например, Java для отделения тестов от источников, заключается в том, что тестирование не встроено в язык, и вы не можете развернуть пакет, не включая все в каталог, включая возможные тесты. Таким образом, в этих языках тесты представляют собой отдельные программы в отдельном дереве исходного кода, запускаемые специальной средой тестирования. Кроме того, возможно создание «разделенных пакетов», в которых исходные коды пакета объединены из разных каталогов, что также невозможно в Go.
Таким образом, обходной путь отделения тестов от производственного кода не требуется, и вы можете легко хранить свои тесты вместе с исходным кодом.
Обратите внимание, что все тесты следует хранить вместе с исходным кодом, а не в отдельных папках, даже файлы с пакетом «_test» для тестирования «черного ящика»:
Тестовые файлы, объявляющие пакет с суффиксом «_test», будут скомпилированы как отдельный пакет, а затем скомпоновать его и запустить с основным тестовым двоичным файлом.
См. пример из стандартной библиотеки.
Почему это важно? Во-первых, ожидается, что go test <packages>
проведет все тесты для целевых пакетов, во-вторых (как в примере выше) тестируемые примеры должны появиться в документации пакета.
Спасибо за такое сравнение Java и Go, теперь это имеет смысл!
Go эффективно различает тестирование «белого ящика» и тестирование «черного ящика». При тестировании «белого ящика» тесты находятся в том же пакете, что и код, который вы хотите протестировать, поэтому у вас есть доступ к частным внутренним компонентам. При тестировании «черного ящика», которое, к сожалению, немного недооценивается в онлайн-статьях, вы помещаете тестовый код в отдельный изолированный пакет, поэтому тестовый код имеет доступ только к общедоступному интерфейсу кода, который вы хотите протестировать.
В документации особо отмечается это разделение.
Цитирую:
Тестовый файл может находиться в том же пакете, что и тестируемый, или в соответствующем пакете с суффиксом «_test».
Если файл находится в отдельном пакете «_test», тестируемый пакет должен быть импортирован явно, и только его экспортированные идентификаторы могут быть использовал. Это известно как тестирование «черного ящика».
package abs_test
import (
"testing"
"path_to_pkg/abs"
)
func TestAbs(t *testing.T) {
// test public abs stuff
}
Это соглашение, которое определяет Go.
Спасибо за это объяснение, оно имеет смысл!
Ваш ответ неверен, хотя тесты черного ящика могут быть объявлены в пакете «_test», они все равно должны находиться в том же каталоге, что и исходные файлы, а не в каком-то подкаталоге.
@eik Хм, это больно. У меня он настроен дома в другой папке на основе существующего проекта, который я нашел в git, быстро погуглил и нашел эту статью, которая подтвердила то, что я считал правдой. Но должен признаться, что я давно не прикасался к настройке.
Как упоминалось в моем ответе , go test your/package
должен запускать все тесты для этого пакета, и вам нужны работоспособные примеры в документации по исходникам. Также посетите стандартную библиотеку или другие популярные проекты. Конечно, вы можете использовать любой макет, который вам нравится, но размещение тестов в разных папках не является «соглашением, которое определяет Go».
Разные языки и инструменты структурируют тесты по-разному. Модульные тесты Go компилируются и запускаются только в одном пакете. Вы помещаете свои модульные тесты в тот же пакет, что и то, что они тестируют. Если вы хотите выполнять тесты вне пакета, вы можете это сделать, но тогда у вас не будет доступа к внутренним компонентам пакета, и вам придется запускать эти тесты отдельно.