Автоматизированное тестирование. Восприятие и особенности
Я уже писал ранее о важности автотестирования и его роли в развитии продукта - https://set.ki/post/gLHJxHP Сегодня же хотел бы взглянуть на эту тему с другой стороны и обсудить восприятие тестирования в целом, и автотестирования в частности, разработчиками, а также особенности создания платформ и фреймворков для автотестирования.
К сожалению, исходя из личного опыта, могу сказать, что обеспечение качества продукта через тестирование часто недооценивается. Несмотря на то, что уже написано множество книг авторитетными авторами и разработаны различные методики, среди которых лидирует TDD (test-driven development), многие разработчики до сих пор относятся к этому крайне халатно, считая, что тестирование «не приносит ценности бизнесу».
Мне довелось работать на самых разных проектах: это и системы мониторинга, и эксплуатационные платформы, и финансовые решения. И, к сожалению, далеко не везде был достигнут приемлемый уровень обеспечения качества. При этом продукты зачастую были критически важными и оказывали прямое влияние на пользователей. Юнит-тесты либо отсутствовали вовсе, либо были настолько искажены, что уже не могли считаться юнит-тестами, требуя развертывания дополнительного окружения и баз данных. При этом к полноценным интеграционным тестам разработчики относились с большим скептицизмом.
Создание полноценной платформы или фреймворка для тестирования — задача далеко не тривиальная, а порой даже более сложная, чем разработка основного продукта. Это связано с рядом особенностей:
1. Удобство использования. Инструмент должен быть интуитивно понятным и удобным. Например, в случае с API необходимо предусмотреть нативный механизм отправки запросов с различными заголовками, включая некорректные данные для проверки негативных сценариев.
2. Нарушение паттернов проектирования. Для воспроизведения нестандартных сценариев иногда приходится осознанно нарушать общепринятые паттерны проектирования.
3. Обход ограничений языков программирования. Для языков, которые защищают разработчиков от ошибок, таких как Null Pointer Exception, приходится использовать приемы, позволяющие обойти встроенные ограничения.
4. Логическая сложность. В продуктах с многоступенчатой логикой, где каждый последующий этап зависит от результата предыдущего, необходимо воспроизвести эту логику, не превращая код в портянки из условий if, которые потом будет сложно поддерживать.
5. Гибкость тестовых данных. Необходимо предусмотреть механизм отбора тестовых данных, который будет адаптироваться под конкретную реализацию продукта.
Этот список далеко не полный, но он уже позволяет понять, с какими фундаментальными проблемами приходится сталкиваться при создании системы тестирования.
Что касается выбора технологий, популярным подходом считается использование того же стека, что и для основного продукта. Однако, на мой взгляд, это не всегда оправдано. Если в вашей зоне ответственности находится конкретный стек, то, конечно, лучше писать тесты на нем. Но это скорее исключение. Чаще всего продукт состоит из множества компонентов: бэкенд, мобильные приложения, веб-клиенты, IoT-устройства и т.д. В таких случаях лучше выбрать стек, который можно использовать во всех слоях приложения (или хотя бы в большинстве из них). Это упростит как поддержку в долгосрочной перспективе, так и подбор инженеров.