Я хочу выполнить модульные тесты над структурой, которую я закодировал в golang. Однако у меня есть повторяющиеся задачи, которые я не хочу каждый раз явно повторять вручную. Тем не менее, мне нравится помещать их в функцию BeforeEach, а затем заставлять каждый тест выполнять ее перед запуском, не вызывая ее явным образом внутри теста. Есть ли способ сделать это?
Чтобы дать некоторый контекст, возьмите этот тест в качестве примера. Как переместить часть настройки во внешнюю функцию, не вызывая ее в каждом тесте?
func TestBootstrap_LoadError(t *testing.T) {
// Setup
mockedLoader := new(MockLoader)
env.SetLoader(mockedLoader)
// Given
mockedLoader.On("Load", mock.Anything).Return(errors.New("error loading .env file"))
envService := env.EnvService()
// Test
err := envService.Bootstrap()
// Assertions
assert.Error(t, err)
assert.False(t, envService.IsBootstrapped())
}
Обычно я делаю что-то вроде этого:
func TestSuite(t *testing.T) {
var mockedLoader *Loader
run := func(name string, fn func()) {
mockedLoader := new(MockLoader)
env.SetLoader(mockedLoader)
t.Run(name, fn())
}
run("Test Bootstrap Load Error", func() {
mockedLoader.On("Load", mock.Anything).Return(errors.New("error loading .env file"))
envService := env.EnvService()
// Test
err := envService.Bootstrap()
assert.Error(t, err)
assert.False(t, envService.IsBootstrapped())
})
}
Где все, что имеет один и тот же код установки, будет в одном тесте «набора», и я, по сути, перехватываю t.Run
, чтобы запустить код установки для себя.
В пакете стандартной библиотеки testing
есть специальная TestMain
функция, которая может быть объявлена один раз для каждого (тестового) пакета и запускаться один раз для всех тестов. Он имеет функцию для запуска тестов и может использоваться для размещения кода настройки и демонтажа для всех тестов в пакете.
func TestMain(m *testing.M) {
setup()
// runs all tests in the package
exitCode := m.Run()
teardown()
os.Exit(exitCode)
}
Одним из недостатков TestMain
является то, что вам необходимо передавать переменные настройки (например, фиктивное или реальное соединение с БД) в тесты через глобальные тестовые переменные. Невозможно передать их непосредственно в тесты.
Если вы хотите использовать стандартную библиотеку, имеющую функцию, которую можно вызывать в каждом тесте для настройки и одну для демонтажа, это вариант, если вам нужна настройка и демонтаж для каждого теста. Здесь переменные можно легко передавать в функции настройки/демонтажа и из них.
func TestExample(t *testing.T) {
setup()
defer teardown()
// test code
}
Существуют и другие библиотеки модульных тестов, которые имеют больше возможностей по настройке и демонтажу. Например, пакет suite пакета testify способен группировать тесты в пакет и выполнять настройку и демонтаж каждого пакета. Несколько пакетов можно объединить в один (тестовый) пакет, что обеспечивает более детальную настройку и контроль демонтажа. Кроме того, он также добавляет больше опций, помимо одной функции настройки и одной функции демонтажа для всего пакета. См. документы.
Переменными можно управлять отдельно, и они не загрязняют глобальное пространство переменных.
Обычно я придерживаюсь того, что описал в разделе Test Setup
. Этого плюс использование подтестов обычно достаточно для контроля над настройкой и демонтажем. См. также этот ответ, чтобы узнать об умном способе управления настройкой и демонтажем для каждого подтеста.
Никогда не использовал ginkgo
сам
В итоге я использовал github.com/stretchr/testify . Я также видел Ginkgo ( github.com/onsi/ginkgo), который поставляется с этим стилем BDD, но с ним есть некоторые проблемы. Это правда?