Когда проект на Go растёт, тесты часто скатываются в один гигантский
*_test.go. В него свалено всё подряд. Настройка окружения, рукописные моки репозитория и сервиса, проверка бизнес логики, симуляция HTTP. Сначала удобно, потом файл пухнет до тысяч строк. В этой части разберём, чем это плохо и как вынести моки в одно место.⚙️ Две боли монолита
Первое, разрастание кода. Файл с сетапом, табличными кейсами и подробными моками превращается в нечитаемое полотно, по которому невозможно навигироваться.
Второе, циклические импорты. В Go пакеты не могут импортировать друг друга по кругу. Когда моки, доменная логика и HTTP транспорт плотно связаны в тестах, границы между пакетами базы, сервиса и хендлера размываются, и компилятор падает с ошибкой циклической зависимости.
⚙️ Решение — разделить по ответственности
Монолит разбивается на три файла внутри тестового пакета:
package_test/
mock.go // общие моки сервиса и репозитория
*_service_test.go // юнит тесты бизнес логики
*_handler_test.go // HTTP, роутинг, валидация
Моки в одном месте
Вместо копипаста по разным файлам все структуры заглушек объявляются один раз в отдельном
mock.go. Это единый источник правды для тестовых дублей, и именно вынос моков убирает циклические импорты:type MockAuthRepository struct {
GetUsernameOrEmailFunc func(ctx context.Context, username string) (*models.Users, error)
RegisterFunc func(ctx context.Context, user *models.Users) error
}
func (m *MockAuthRepository) GetUsernameOrEmail(ctx context.Context, username string) (*models.Users, error) {
if m.GetUsernameOrEmailFunc != nil {
return m.GetUsernameOrEmailFunc(ctx, username)
}
return &models.Users{}, nil
}Один файл с тестами это удобный старт и плохой финал. Разрастание кода и циклические импорты лечатся выносом моков в
mock.go и разбиением тестов на слои. В части 2 покажем тесты бизнес логики и HTTP слоя, а также трейдоффы подхода.📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction