Ответ
Модульное (unit) и интеграционное тестирование — это два разных уровня в пирамиде тестирования, каждый из которых преследует свои цели.
Модульные тесты (Unit Tests)
- Цель: Проверить корректность работы наименьшей изолированной части кода — "юнита" (обычно это одна функция или метод).
- Область: Очень маленькая и сфокусированная. Тестируется только логика внутри юнита.
- Изоляция: Все внешние зависимости (базы данных, файловая система, сетевые вызовы, другие сервисы) должны быть заменены моками (mocks) или стабами (stubs). Это гарантирует, что тест проверяет только тестируемый код, а не его зависимости.
- Скорость: Очень быстрые, так как не требуют запуска внешних систем. Их должно быть много.
Пример (проверка функции Add
):
func Add(a, b int) int {
return a + b
}
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Ожидали 5, получили %d", result)
}
}
Интеграционные тесты (Integration Tests)
- Цель: Проверить, что несколько компонентов системы корректно взаимодействуют друг с другом. Они проверяют "швы" и контракты между модулями.
- Область: Шире, чем у unit-тестов. Например, взаимодействие вашего сервиса с базой данных, с очередью сообщений или с другим API.
- Изоляция: Частичная. Внешние системы (БД, API) не мокаются, а используются их реальные или тестовые экземпляры (например, тестовая база данных, запущенная в Docker).
- Скорость: Значительно медленнее, чем unit-тесты, так как требуют настройки окружения и реальных I/O операций.
Пример (проверка создания пользователя в БД):
// db - это реальное подключение к тестовой базе данных
func TestUserCreation(t *testing.T) {
// 1. Настройка: подключение к тестовой БД и очистка таблиц
db, cleanup := setupTestDB(t)
defer cleanup() // 3. Очистка после теста
repo := NewUserRepository(db)
// 2. Действие: вызов метода, который работает с реальной БД
err := repo.CreateUser("test@example.com", "password123")
if err != nil {
t.Fatalf("Не удалось создать пользователя: %v", err)
}
// Можно добавить проверку, что пользователь действительно появился в БД
}
Сравнительная таблица
Характеристика | Модульные тесты (Unit) | Интеграционные тесты (Integration) |
---|---|---|
Цель | Корректность отдельного модуля в изоляции | Корректность взаимодействия между модулями |
Зависимости | Заменяются моками/стабами | Используются реальные (или тестовые экземпляры) |
Скорость | Очень высокая | Средняя / Низкая |
Количество | Много (основа пирамиды тестирования) | Меньше, чем модульных |
Обнаруживаемые ошибки | Ошибки в алгоритмах и логике внутри функции | Ошибки в контрактах API, конфигурации, схеме БД, сетевом взаимодействии |
Заключение: Оба типа тестов критически важны. Unit-тесты обеспечивают надежность отдельных кирпичиков, а интеграционные тесты — что эти кирпичики правильно складываются в стену.