Мы вынесли моки в
mock.go и наметили разбиение тестов на слои. Теперь покажем сами тесты двух слоёв и честно разберём, чем платим за такую структуру.🛠 Бизнес логика (`*_service_test.go`)
Этот файл проверяет только доменную логику. Слой репозитория замокан через
mock.go, поэтому тесты гоняются целиком в памяти и работают очень быстро. Здесь проверяют правила валидации, обработку кривых данных, доменные ошибки и переходы состояний:
func TestAuthServiceLogin(t *testing.T) {
t.Run("login credentials", func(t *testing.T) {
testAuthRepo.GetUsernameOrEmailFunc = func(ctx context.Context, username string) (*models.Users, error) {
hash, _ := bcrypt.GenerateFromPassword([]byte("!Abc1234"), bcrypt.DefaultCost)
return &models.Users{ID: 1, Username: "test_account", Password: string(hash)}, nil
}
req := auth.LoginRequest{Username: "rdev", Password: "!Abc1234"}
_, err := testAuthSvc.Login(context.Background(), req)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
}🛠 HTTP слой (`*_handler_test.go`)
Этот файл проверяет, как API общается с внешним миром. Он поднимает запросы через
net/http/httptest и использует моки сервиса, чтобы не дёргать реальную логику. Под проверкой статус коды, сериализация JSON, параметры запроса, заголовки, работа мидлварей вроде rate limiter. Табличный тест гоняет несколько кейсов входа сразу:
func TestAuthHandlerLogin(t *testing.T) {
tests := []struct {
name string
requestBody any
expectedStatus int
}{
{"complete credentials", loginRequest{"rdev", "!Abc1234"}, http.StatusOK},
{"no password", loginRequest{"rdev", ""}, http.StatusBadRequest},
{"password too short", loginRequest{"rdev", "1234"}, http.StatusBadRequest},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, w := helpers.SetupJSONTestContext(t, http.MethodPost, "/login", tt.requestBody)
testAuthHandler.Login(ctx)
if w.Code != tt.expectedStatus {
t.Errorf("Login() status = %d, want %d", w.Code, tt.expectedStatus)
}
})
}
}❔ Чем платим
Плюсы:
• баги в роутинге ищутся в тесте хендлера
• баги в расчётах ищутся в тесте сервиса
• изоляция моков снимает циклические импорты
• границы слоёв не дают случайно проверить механику HTTP внутри теста логики
Минусы:
• чуть больше бойлерплейта
• несколько файлов требуют начальной настройки
• при изменении интерфейса сервиса
mock.go придётся править руками, если не подключить генератор вроде mockery.Разделение тестов по ответственности это проверенная для Go стратегия. Изолируете HTTP логику от бизнес логики, выносите моки в один файл и получаете набор тестов, который не разрастается, не ломается циклическими импортами и легко читается.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction