Тестування в Go у 2026: модульні тести, моки та питання технічних співбесід
Опануйте тестування в Go зі стандартною бібліотекою, табличними тестами, моками та патернами, які очікують на співбесідах. Практичні приклади з testify, gomock та пакетом testing.

Тестування в Go базується на стандартному пакеті testing, який поставляється з кожною інсталяцією Go і не потребує жодних зовнішніх залежностей. На відміну від фреймворків в інших мовах, підхід Go надає перевагу простоті: тестові файли знаходяться поруч з продакшн кодом, тестові функції дотримуються конвенції іменування, а команда go test обробляє виявлення та виконання тестів.
На кандидатів, які пишуть табличні тести, використовують інтерфейси для впровадження залежностей і розуміють, коли мокування додає цінність, а коли лише зайву складність.
Написання модульних тестів з пакетом testing
Кожен тестовий файл закінчується на _test.go і знаходиться в тому ж пакеті, що й код, який тестується. Тестові функції починаються з Test, за яким йде назва з великої літери. Параметр *testing.T надає методи для звітування про помилки.
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}Виконання go test ./... запускає всі тести в поточному модулі. Прапорець -v показує назви окремих тестів та їх статус pass/fail.
Табличні тести: стандарт Go
Табличні тести зменшують дублювання і роблять додавання нових випадків тривіальним. Кожен рядок у таблиці представляє один сценарій з вхідними даними та очікуваними результатами. Цей патерн зустрічається в стандартній бібліотеці Go та в продакшн кодових базах по всій індустрії.
package validator
import "testing"
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{"valid email", "user@example.com", false},
{"missing at sign", "userexample.com", true},
{"empty string", "", true},
{"unicode local part", "user@例え.jp", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEmail(tt.email)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateEmail(%q) error = %v, wantErr %v",
tt.email, err, tt.wantErr)
}
})
}
}Метод t.Run створює підтести, які виконуються незалежно. Невдалі підтести повідомляють, який конкретний випадок провалився, не зупиняючи інші випадки.
Впровадження залежностей через інтерфейси
Інтерфейси Go дозволяють тестувати код, який залежить від зовнішніх систем: баз даних, HTTP клієнтів, файлових систем. Визначення мінімального інтерфейсу в місці використання дозволяє замінювати реальні імплементації на тестові дублери.
package order
// Repository defines the data access methods this service needs
type Repository interface {
FindByID(id string) (*Order, error)
Save(order *Order) error
}
// Service handles order business logic
type Service struct {
repo Repository
}
// NewService creates a service with the given repository
func NewService(repo Repository) *Service {
return &Service{repo: repo}
}
// Process validates and saves an order
func (s *Service) Process(order *Order) error {
if order.Total <= 0 {
return ErrInvalidTotal
}
return s.repo.Save(order)
}Service приймає будь-який тип, що задовольняє Repository. Продакшн код передає імплементацію на основі бази даних. Тести передають мок або стаб.
Мокування з gomock та mockgen
Пакет gomock генерує мок-імплементації з визначень інтерфейсів. Команда mockgen читає вихідні файли і створює мок-структури, які записують виклики та повертають налаштовані значення.
# Generate mocks for the Repository interface
mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocksВикористання згенерованого моку в тестах:
package order
import (
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"yourmodule/order/mocks"
)
func TestService_Process_SavesValidOrder(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
order := &Order{ID: "123", Total: 99.99}
// Expect Save to be called once with this order, return nil
mockRepo.EXPECT().
Save(order).
Return(nil).
Times(1)
svc := NewService(mockRepo)
err := svc.Process(order)
assert.NoError(t, err)
}
func TestService_Process_RejectsZeroTotal(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
// No calls expected to repo since validation fails first
svc := NewService(mockRepo)
err := svc.Process(&Order{ID: "456", Total: 0})
assert.ErrorIs(t, err, ErrInvalidTotal)
}Мок перевіряє, що Save була викликана рівно один раз з очікуваним аргументом. Якщо код, що тестується, ніколи не викликає Save або викликає її з іншими аргументами, тест провалюється.
Використання testify для assertions та test suites
testify надає функції assertions, які створюють чіткіші повідомлення про помилки, ніж ручні if-перевірки. Пакет assert продовжує виконання після помилок. Пакет require негайно зупиняє тест.
package user
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseUser(t *testing.T) {
input := `{"id": "u1", "name": "Alice"}`
user, err := ParseUser(input)
require.NoError(t, err, "parsing should not fail")
assert.Equal(t, "u1", user.ID)
assert.Equal(t, "Alice", user.Name)
assert.Empty(t, user.Email, "email should default to empty")
}Виклик require.NoError зупиняє тест, якщо парсинг не вдається, запобігаючи панікам nil pointer у наступних assertions.
Готовий до співбесід з Go?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Тестування HTTP хендлерів з httptest
Пакет net/http/httptest надає ResponseRecorder для захоплення виводу хендлера та Server для запуску локального тестового сервера. Більшість модульних тестів використовують ResponseRecorder, щоб уникнути мережевого навантаження.
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHealthHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rec := httptest.NewRecorder()
HealthHandler(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, `{"status": "ok"}`, rec.Body.String())
}Для хендлерів, що викликають зовнішні сервіси, впроваджуйте мок-клієнт або використовуйте httptest.NewServer для створення фейкового бекенду.
Поширені питання співбесід про тестування в Go
Інтерв'юери оцінюють знання тестування через питання, які розкривають досвід роботи з реальними кодовими базами. Ось патерни, що відрізняють підготовлених кандидатів:
"Як би ви протестували функцію, що викликає зовнішній API?"
Визначте інтерфейс для HTTP клієнта, впровадьте його у функцію або структуру та надайте мок, що повертає заздалегідь визначені відповіді. Це усуває мережеві виклики і робить тести детермінованими.
"Коли б ви використовували стаб замість моку?"
Стаби повертають заготовлені відповіді без перевірки того, як їх викликали. Моки перевіряють, що певні методи були викликані з певними аргументами. Використовуйте стаби, коли повернене значення важливіше за взаємодію. Використовуйте моки, коли перевірка взаємодії є метою тесту.
"Що таке табличні тести і чому Go їх надає перевагу?"
Табличні тести визначають тестові випадки як дані в slice структур. Вони зменшують boilerplate, роблять додавання випадків тривіальним і створюють читабельний тестовий вивід з t.Run. Патерн відповідає перевазі Go явного, повторюваного коду над хитрими абстракціями.
"Як ви обробляєте тестові фікстури або setup, що спільний для кількох тестів?"
Використовуйте TestMain для setup та teardown на рівні пакету. Використовуйте допоміжні функції або тестові набори (з testify) для спільного setup між пов'язаними тестами. Уникайте глобального стану, що створює зв'язок між тестами.
Готуєтесь до співбесіди з Go? Модуль тестування Go детально розглядає ці патерни з практичними питаннями.
Запуск тестів з покриттям та виявленням гонок
Команда go test приймає прапорці, що виявляють непротестовані шляхи коду та помилки конкурентності.
# Run tests with coverage report
go test -cover ./...
# Generate HTML coverage visualization
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Detect race conditions (slower, but catches real bugs)
go test -race ./...Детектор гонок інструментує доступ до пам'яті та позначає одночасні читання та записи до однієї змінної. Запуск тестів з -race в CI виловлює помилки, які проявляються лише при певному таймінгу.
Організація тестів у великих кодових базах
Зі зростанням проектів організація тестів впливає на підтримуваність:
- Тести в тому ж пакеті (
package foo) мають доступ до неекспортованих функцій та полів. Використовуйте для модульних тестів, що перевіряють внутрішню поведінку. - Тести у зовнішньому пакеті (
package foo_test) імпортують пакет як зовнішній код. Використовуйте для інтеграційних тестів та для перевірки публічного API. - Каталоги testdata зберігають фікстури, такі як JSON файли, golden outputs або seed бази даних. Go ігнорує їх під час збірки.
- Build tags відділяють модульні тести від інтеграційних тестів, що потребують зовнішніх систем. Запустіть
go test -tags=integration ./..., щоб їх включити.
Більше про найкращі практики Go поза тестуванням можна знайти в статті про патерни конкурентності, яка охоплює горутини та канали.
Що запам'ятати про тестування в Go
- Пакет
testingпоставляється з Go і не потребує зовнішніх залежностей - Табличні тести зменшують дублювання і є очікуваним патерном на співбесідах
- Інтерфейси забезпечують впровадження залежностей; визначайте їх у місці використання, а не в імплементації
gomockгенерує моки з інтерфейсів;testifyнадає чистіші assertionshttptest.ResponseRecorderзахоплює вивід хендлера без мережевого навантаження- Прапорець
-raceвиявляє помилки конкурентності, які модульні тести інакше пропускають - Метрики покриття спрямовують увагу, але не гарантують коректність
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Чи знайдеш ти помилку в Go?
Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Автор:
Anthony Fillion-MailletЗасновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 24 серпня 2026 р.
Теги
Поділитися
Пов'язані статті

Go Generics у 2026: Параметри Типів, Обмеження та Питання на Співбесіді
Повний посібник з дженериків Go для підготовки до технічних співбесід. Параметри типів, обмеження, оператор тильди та практичні приклади коду.

Обробка помилок у Go у 2026 році: патерни, обгортання та питання технічних співбесід
Вичерпний посібник з обробки помилок у Go: інтерфейс error, сигнальні помилки, обгортання з %w, errors.Is, errors.As та питання, що зустрічаються на технічних співбесідах.

Go 1.26 на співбесіді: Green Tea GC, go fix та оптимізація стеку
Ключові питання та відповіді з Go 1.26 для технічних співбесід: збирач сміття Green Tea зі зниженням навантаження на 10-40%, оновлений go fix з модернізаторами, алокація slice на стеку, виявлення витоків горутин та постквантова криптографія.