Оглавление
- 1. Введение в тестирование ПО
- 2. Зачем нужны тесты
- 3. Основные определения
- 4. Классификация тестов
- 5. Пирамида тестирования
- 6. Модульное (Unit) тестирование в Go
- 7. Паттерн AAA (Arrange, Act, Assert)
- 8. Основные правила и соглашения тестирования в Go
- 9. Использование моков (Test Doubles)
- 10. GoMock: основные возможности
- 11. Лучшие практики использования моков
- 12. Популярные библиотеки для тестирования
- 13. Итоги и ключевые принципы
1. Введение в тестирование ПО
- Тестирование — процесс проверки программного обеспечения на наличие ошибок.
- Главная цель тестирования — обеспечение надёжности и качества кода.
- Тестирование — не гарантирует полного отсутствия ошибок, но снижает риски их появления в production.
2. Зачем нужны тесты
- Надёжность: Дают уверенность, что новый функционал не ломает уже реализованный.
- Чистота архитектуры: Способствуют написанию слабо связанного, тестируемого и поддерживаемого кода.
- Безопасный рефакторинг: Позволяют менять код, будучи уверенным в сохранении его поведения.
- Живая документация: Тесты показывают, как должен работать код и использоваться интерфейсы.
3. Основные определения
- Тестирование: процесс поиска ошибок в ПО.
- Тестирование находит ошибки, но не доказывает их отсутствие.
4. Классификация тестов
Тесты классифицируются по нескольким критериям:
По цели:
- Функциональное: Проверяет ЧТО делает система (соответствие требованиям).
- Нефункциональное: Проверяет КАК система работает (производительность, безопасность, надёжность).
По методу доступа к коду:
- Чёрный ящик (Black box): Без знания о внутреннем устройстве.
- Белый ящик (White box): С полным знанием исходного кода.
- Серый ящик (Grey box): Частичное знание устройства системы.
По степени автоматизации:
- Ручное
- Автоматическое
По уровню:
- Модульное (Unit): Изолированное тестирование отдельных функций/методов.
- Интеграционное: Проверка взаимодействия между компонентами.
- Сквозное (End-to-End, e2e): Тестирование полной пользовательской цепочки.
5. Пирамида тестирования
Модель для балансировки типов тестов по затратам и эффективности:
- Основание (Unit-тесты):
- Самый многочисленный уровень.
- Быстрые, дешёвые, изолированные.
- Работают по принципу “белого ящика”.
- Середина (Интеграционные):
- Меньше по численности, чем Unit.
- Проверяют взаимодействие модулей.
- Медленнее, требуют дополнительной инфраструктуры.
- Вершина (End-to-End):
- Самые редкие, дорогие и медленные.
- Проверяют систему с точки зрения пользователя (“чёрный ящик”).
Фундаментальная концепция: большинство тестов в проекте — это Unit-тесты.
6. Модульное (Unit) тестирование в Go
- Модульные тесты в Go предназначены для изолированного тестирования отдельных компонентов.
- Упор на чеклист фундаментальных принципов: изоляция, независимость, повторяемость.
7. Паттерн AAA (Arrange, Act, Assert)
Классическая структура для написания читаемых тестов:
- Arrange (Подготовка):
- Инициализация всех нужных данных и окружения.
- Act (Действие):
- Вызов тестируемой функции или метода.
- Assert (Проверка):
- Сравнение полученного результата с ожидаемым.
Этот паттерн помогает поддерживать логику и повторяемость тестов.
8. Основные правила и соглашения тестирования в Go
- Все тесты должны быть помещены в файлы с суффиксом
_test.go. - Каждая тестовая функция:
- Начинается с префикса
Test - Принимает аргумент
t *testing.T - Не возвращает значений
- Начинается с префикса
9. Использование моков (Test Doubles)
- Моки (Mocks) — разновидность тестовых двойников (Test Doubles).
- Тестовый двойник: любой объект, имитирующий реальный компонент с целью изоляции тестируемого кода.
- Назначение моков:
- Имитация зависимостей.
- Фокус на бизнес-логике без обращения к внешним системам.
- Создание моков:
- Ручное (для простых интерфейсов)
- Автоматическое (генераторы моков, например, GoMock)
10. GoMock: основные возможности
- GoMock — инструмент для гибкой настройки моков в тестах Go.
- Ключевые методы и возможности:
mock.EXPECT(): начало сценария ожидания вызова.MethodName(...): указание ожидаемого метода.gomock.Any(),gomock.Eq(): настройка ожидаемых аргументов..Return(...): определение возвращаемых значений..Times(1),.AnyTimes(): сколько раз ожидается вызов метода.gomock.InOrder(...): задание строгой последовательности вызовов.
11. Лучшие практики использования моков
- Мокайте только внешние зависимости.
- Не используйте моки там, где можно протестировать реальным объектом.
- Простота моков:
- Моки должны содержать минимальное количество логики, чтобы не стать источником багов.
- Выбирайте стратегию проверки:
- Моки нужны в основном для проверки вызовов (что сервис A вызывает метод сервиса B).
- В большинстве случаев лучше проверять конечное состояние системы, а не факт вызова.
12. Популярные библиотеки для тестирования
Testify
- Де-факто стандарт для тестирования в Go.
- Функции:
- Утверждения (Assertions): удобные методы для проверки (assert, require).
assert: фиксация ошибки, продолжение выполнения.require: при ошибке тест завершает выполнение немедленно.
- Встроенные моки для тестирования зависимостей.
- Тестовые наборы (Suites): групировка тестов и методы жизненного цикла (
SetupTest,TearDownTestи т.д.)
- Утверждения (Assertions): удобные методы для проверки (assert, require).
ozon/allure-go
- Генерирует наглядные HTML-отчеты в формате Allure.
- Преимущества:
- Яркие отчеты по шагам, статусу, времени выполнения.
- Группировка тестов и хуки
Before/Afterдля подготовки/завершения. - Шаги (Steps): явное логическое деление теста.
- Метки (Labels): поддержка метаданных Allure для фильтрации и классификации.
13. Итоги и ключевые принципы
- Проблемы тестирования: нестабильные тесты, сложность окружения, скрытые зависимости.
- Принцип инверсии зависимостей (DIP): код должен зависеть от абстракций (интерфейсов), это делает код модульным и тестируемым.
- Интеграционные тесты: важны для проверки взаимодействий, но требуют дополнительных усилий.
- Моки: позволяют изолировать бизнес-логику от внешних зависимостей и упростить модульное тестирование.
- Библиотеки: Testify — удобные проверки и моки, allure-go — визуализация результатов.
- Главная мысль: постоянное совершенствование подходов к тестированию — ключевой путь к созданию надёжного production-кода.
Фундаментальные концепции, которые должны повторяться:
- Unit-тесты — основа качественного тестирования, их должно быть больше всего.
- Тестирование не гарантирует полное отсутствие ошибок, но критично для обнаружения проблем.
- Инверсии зависимостей и использование интерфейсов — фундаментальный путь к тестируемости и модульности кода.