Структурирование тестов в подпапках с помощью Golang

Проект, с которого я начал 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 компилируются и запускаются только в одном пакете. Вы помещаете свои модульные тесты в тот же пакет, что и то, что они тестируют. Если вы хотите выполнять тесты вне пакета, вы можете это сделать, но тогда у вас не будет доступа к внутренним компонентам пакета, и вам придется запускать эти тесты отдельно.

JimB 13.08.2024 18:10

«Я привык, что тесты размещаются в зеркальной структуре папок». Вам придется привыкнуть к другому способу размещения тестов. «Кажется, я не понимаю, как Go структурирует тесты» Go организован в виде пакетов. Код и тесты пакета находятся в одной папке. Вы не можете импортировать «тестовый код». Каждый пакет должен быть автономным, включая тесты.

Volker 13.08.2024 18:11

@Volker, тогда почему go-blueprint создает приложение с папкой tests? Не является ли это заблуждением?

Yanick Rochon 13.08.2024 18:52

@JimB, тогда почему go-blueprint создает приложение с папкой tests? Не является ли это заблуждением?

Yanick Rochon 13.08.2024 18:53

@YanickRochon, вам придется спросить их или обратиться к документации, это не является требованием языкового инструментария. Я предполагаю, что это репозиторий для различных интеграционных тестов, которые не умещаются в одном пакете.

JimB 13.08.2024 18:58

@JimB Я все еще не понимаю. Смотрите, если у меня есть файл в папке tests, то go test найдет его автоматически. Если у меня есть тесты вместе с файлами под internal, то Go не найдет их, пока я не найду go test ./..., но он также найдет другие файлы .go. Это крайне противоречиво.

Yanick Rochon 13.08.2024 19:05
go test сам по себе ничего не находит, без идентификатора пакета он предполагает, что пакет находится в текущем рабочем каталоге, и аналогичен go test .. Аргумент ./... — это подстановочный знак, который включает пакеты в текущем рабочем каталоге и во всех подкаталогах.
JimB 13.08.2024 19:09

«Если у меня есть файл в папке тестов, то go test найдет его автоматически» — это фактически неверное утверждение, которое не соответствует фактическому поведению go test. «Если у меня есть тесты вместе с файлами во внутренней папке, то Go не найдет их, пока я не пройду тест ./...» снова фактическая ошибка. Внутренние пакеты не отличаются от любого другого пакета в отношении тестирования. Вы либо делаете go test в пакете, либо go test full/package/import/path. «Это крайне противоречиво» только потому, что ваши предположения о том, как работает тест go, не соответствуют фактическому поведению.

Volker 13.08.2024 21:11

Просто отметим, что вам следует оформить заказ pkg.go.dev/github.com/stretchr/testify/suite package. Помог мне организовать тесты, аналогичные PHPUnit.

Bilal 14.08.2024 17:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
9
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Тесты Go обычно живут в том же пакете , что и исходные файлы. Даже go-blueprint недавно исправили свои шаблоны. Если вам нравятся более идиоматические шаблоны проектов, возможно, вам стоит взглянуть на gonew.

Смысл, например, Java для отделения тестов от источников, заключается в том, что тестирование не встроено в язык, и вы не можете развернуть пакет, не включая все в каталог, включая возможные тесты. Таким образом, в этих языках тесты представляют собой отдельные программы в отдельном дереве исходного кода, запускаемые специальной средой тестирования. Кроме того, возможно создание «разделенных пакетов», в которых исходные коды пакета объединены из разных каталогов, что также невозможно в Go.

Таким образом, обходной путь отделения тестов от производственного кода не требуется, и вы можете легко хранить свои тесты вместе с исходным кодом.


Обратите внимание, что все тесты следует хранить вместе с исходным кодом, а не в отдельных папках, даже файлы с пакетом «_test» для тестирования «черного ящика»:

Тестовые файлы, объявляющие пакет с суффиксом «_test», будут скомпилированы как отдельный пакет, а затем скомпоновать его и запустить с основным тестовым двоичным файлом.

См. пример из стандартной библиотеки.

Почему это важно? Во-первых, ожидается, что go test <packages> проведет все тесты для целевых пакетов, во-вторых (как в примере выше) тестируемые примеры должны появиться в документации пакета.

Спасибо за такое сравнение Java и Go, теперь это имеет смысл!

Yanick Rochon 14.08.2024 16:58
Ответ принят как подходящий

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

В документации особо отмечается это разделение.

https://pkg.go.dev/testing

Цитирую:

Тестовый файл может находиться в том же пакете, что и тестируемый, или в соответствующем пакете с суффиксом «_test».

Если файл находится в отдельном пакете «_test», тестируемый пакет должен быть импортирован явно, и только его экспортированные идентификаторы могут быть использовал. Это известно как тестирование «черного ящика».

package abs_test

import (
  "testing"

  "path_to_pkg/abs" 
)

func TestAbs(t *testing.T) {
  // test public abs stuff
}

Это соглашение, которое определяет Go.

  • Тест белого ящика: поместите тесты в файл yourcode_test.go.
  • Тест «черного ящика»: поместите тесты в подкаталог yourcode_test/yourcode_test.go.

Спасибо за это объяснение, оно имеет смысл!

Yanick Rochon 14.08.2024 16:58

Ваш ответ неверен, хотя тесты черного ящика могут быть объявлены в пакете «_test», они все равно должны находиться в том же каталоге, что и исходные файлы, а не в каком-то подкаталоге.

eik 15.08.2024 07:05

@eik Хм, это больно. У меня он настроен дома в другой папке на основе существующего проекта, который я нашел в git, быстро погуглил и нашел эту статью, которая подтвердила то, что я считал правдой. Но должен признаться, что я давно не прикасался к настройке.

Gimby 15.08.2024 14:43

Как упоминалось в моем ответе , go test your/package должен запускать все тесты для этого пакета, и вам нужны работоспособные примеры в документации по исходникам. Также посетите стандартную библиотеку или другие популярные проекты. Конечно, вы можете использовать любой макет, который вам нравится, но размещение тестов в разных папках не является «соглашением, которое определяет Go».

eik 15.08.2024 15:22

Другие вопросы по теме