- Почему необходимо
- Распространенные баги
- Сложности
- Типы тестирования API:
- Лучшие практики
- На каком уровне: юнит- или интеграционном
Мобильное приложение падает из-за бага, от этого страдает один человек; когда падает API, пострадает множество людей, возможно даже миллионы. В банковских приложениях это очень критично. Ошибки в API провоцируют каскад трудноуловимых «цепных» ошибок. Поэтому нужно тестирование API — чтобы гарантировать корректность кода и рано выявлять баги, пока они не принесли вреда на высоких уровнях всем клиентам/потребителям.
Итак, чем примечательно тестирование API: это тип QA-операций, в которых команда проверяет корректность программного кода, не имеющего пользовательского интерфейса (GUI). Это делает API-тестирование более «ориентированным на код», чем стандартное тестирование, например интерфейса. QA-команды тестируют API, верифицируя функциональность, производительность и безопасность API.
Что дает тестирование API
- Верификация функционирования API
- Раннее выявление багов, то есть на ранних этапах цикла разработки
- Тестирование API, в конце концов очень неплохой способ «прокачать» новых членов команды, малоопытных в программировании и тестировании, поощрить их не бояться «сломать» функции
- Автоматизация такого тестирования (а она как правило внедрена) уменьшает время доставки продукта, команде нужно меньше времени на тестирование изменений и новых функций.
Программы вообще, и API в частности, могут быть «инфицированы» багами самых разных типов.
Распространенные баги
- Баги в бизнес-логике, например финансовых платежей в банковском приложении
- Баги хранения данных и их передачи, например неспособность сохранять файлы с кириллическими символами в именах
- Нестабильное поведение, например API недоступен время от времени, или увеличивается время ответа до неприемлемого
- Неправильная обработка исключений, например API не возвращает ожидаемый код ошибки, если что-то нужное не найдено
- Неспособность отрабатывать негативные сценарии
Сложности тестирования API
- Конечно, главный челлендж — автоматизация такого сложного тестирования. Чтобы иметь возможность писать надежные автотесты, код должен быть изначально хорошо тестируемый. Это значит, что код автотестов API пишется изначально в расчете на автоматизацию.
- Тестирование API требует довольно-таки высокого уровня скиллов. Тестировщики должны иметь опыт в нужных фреймворках и библиотеках.
- Такое тестирование может быть сложным для небольших QA-команд, нанимаемых «под проект».
Модульное тестирование API
Юнит-тестирование проверяет модули кода (обычно это отдельные функции), независимые и изолированные от других модулей. Разработчики чаще всего сами пишут юнит-тесты своего кода. Существует даже методика разработки TDD (разработка через тестирование).
Пример: онлайн-магазин книг. Нужен API-эндпойнт, который передает данные об авторе в другие модули, а именно:
- Модуль, получающий данные об авторе
- Модуль, получающий названия книг указанного автора
- Модуль, который:
- Обрабатывает кейс ошибки, если автор не найден
- Генерирует ответ из имени автора и названия книг, и возвращает его пользователю
Схема юнит-тестов API:
Преимущества
- Писать юнит-тесты API достаточно быстро
- Тесты быстро выполняются (разработчик получает быстрый результат)
- Все языки программирования имеют специальные библиотеки и фреймворки для юнит-тестирования
Сложности
- В некоторых ситуациях написание юнит-тестов API может требовать много времени и задержать команду
- Поддержка тестов может быть проблематичной
- Не позволяет выявить ошибки всех типов
Советы
Код должен быть изначально «тестабельный», то есть удобный для юнит-тестов. Иначе уйдет много времени и лишних усилий, и тесты могут оказаться нестабильными, то есть выдавать разные результаты. Нужно соблюдать лучшие практики программирования.
- Разделять большие модули на маленькие
- Стараться, чтобы один модуль имел лишь одну функцию
- В случае модулей, зависящих от других модулей, использовать абстракции типа интерфейсов или внедрений зависимостей, они упрощают процесс и делают код более тестабельным
- Подобрать фреймворк или библиотеку в качестве тест-раннера для выполнения тест-кейсов. Он должен иметь следующие функции:
- Позволяет группировать тесты по категориям
- Легко читать и понимать описание каждого теста
- Запускать все тесты одновременно
- А также часть тестов
- Есть хуки перед выполнением и после
- Интегрируется с assertion-библиотеками
- Assertions являются большой и важной частью автоматизации, поэтому нужен фреймворк (библиотека) со следующей функциональностью:
- Сравнение значений
- Создание кастомных сообщений при assertion-ошибках
- Хорошо работает в связке с выбранным тест-раннером
- Выводит читабельные сообщения об ошибках
- Создать файл с описаниями тест-кейсов
Пример кода на JavaScript. Функция getSlug(), изменяющая введенный текст:
Пример юнит-теста функции getSlug():
На выходе после запуска тестов увидим нечто вроде этого
Интеграционное тестирование API
Также называется синтетическим тестированием API. Интеграционные тесты API проверяют корректность API end-to-end. Таким образом тестируются эндпойнты REST API или запросы к GraphQL API.
Продолжая пример кода из юнит-тестов (который возвращает информацию об авторе и книгах), протестируем логику этого юнита целиком. Диаграмма:
Преимущества интеграционного тестирования API
- Позволяет определить почти все баги, связанные с API
- Во всех языках программирования есть фреймворки и библиотеки для такого тестирования
Сложности
- Не такое «прямое и простое», как юнит-тестирование
- Написание и выполнение, и обслуживание интеграционных тестов медленнее, чем юнит-тестов
Практика
Принято проводить интеграционное тестирование после завершения разработки новой функции. Проще чем с юнит-тестированием, поскольку интеграционное тестирование API проходит уже по принципу черного ящика. Будет нужен тест-раннер, assertion-библиотека, и другие библиотеки, отправляющие запросы к API.
Пример простого API на JavaScript. Пользователь вводит текст, ему возвращается измененный текст, путем отправки POST-запроса в эндпойнт /api/slug:
Существует библиотека Supertest для JavaScript для тестирования API.
На выходе увидим примерно такое:
Тестирование производительности API
Направлено на проверку производительности API при большой нагрузке.
Особенности
- Идентифицирует проблемы в API и в инфраструктуре при большой нагрузке
- Легче определить проблемные места
Сложности
- Требует времени
- И наличия довольно специфического программного и аппаратного обеспечения и инфраструктуры
Лучшие практики тестирования API
Соблюдение общепринятых лучших практик позволяет создавать качественные тесты, которые потом будет легко читать, понимат, выполнять, и поддерживать.
- Хороший тест-кейс выдает простые и понятные сообщения об ошибке
- Выполняется независимо друг от другого, и не требует специального порядка запуска
- Имеет три раздельные секции: Arrange/Act/Assert — паттерн ААА, «Настрой/Действуй/Проверь»
- Нужно группировать релевантные тест-кейсы
- Нужно тестировать и позитивные, и негативные пользовательские пути
- Писать сначала описания тест-кейсов, затем имплементировать
- Код тестов должен быть простым и понятным
- Описания тестов должны четко декларировать предназначение
- Хорошие тест-кейсы не влияют друг на друга
Интеграционное или юнит?
Этот вопрос иногда поднимается. В идеале, стратегия автоматизации должна подразумевать как юнит-, так и интеграционное тестирование API, поскольку они не взаимозаменяемы.
Если не хватает времени, лучше сфокусироваться на интеграционном уровне.
Юнит-тестирование | Интеграционное |
---|---|
Пишут разработчики | Пишут тестировщики вместе с разработчиками |
Разработчики разделяют код на небольшие юниты и тестируют каждый отдельно | Проверка функциональности API end-to-end |
Быстрое выполнение, быстрый фидбек | Не всегда быстрое выполнение и фидбек |
Область тестирования ограничена юнитом | Широкая область тестирования |
Сосредоточено на валидации кода | End-to-end валидация кода бизнес-логики |
Требует хороших скиллов в ЯП | Можно пользоваться инструментами или писать самому |
Белый ящик | Черный ящик |
При изменении кода требует рефакторинга | Не нужен рефакторинг |