Почему автоматизацию тоже нужно проектировать
Как сделать так, чтобы тесты не тормозили бизнес
Все регионы России последовательно расширяют применение цифровых решений и искусственного интеллекта, в том числе и Башкортостан — региональные власти говорят уже о переходе от отдельных пилотов к системной цифровой архитектуре. На этом фоне растет цена программных ошибок: чем больше процессов зависит от цифровых систем, тем дороже обнаруживать дефекты уже после запуска. Инженер по автоматизации тестирования Светлана Иванова рассказывает, почему большое количество автотестов еще не гарантирует надежность программы, как тестовая инфраструктура сама становится источником проблем и сколько компании может стоить отсутствие архитектуры в коде, который должен этот код проверять.
Фото: предоставлено экспертом
Фото: предоставлено экспертом
— Светлана, вы как инженер по автоматизации тестирования следуете довольно интересному принципу — код, который проверяет другой код, сам должен быть полноценным инженерным продуктом. Поясните подробнее, пожалуйста.
— Действительно, автоматизация тестирования считается одним из главных способов ускорить разработку цифровых продуктов: программа сама проверяет новую версию, находит ошибки и позволяет быстрее выпускать обновления. Но у этого подхода есть обратная сторона. Если тесты создавать без продуманной архитектуры, со временем они сами могут стать проблемой: проверки начинают выполняться часами, регулярно дают ложные ошибки, требуют постоянных ручных исправлений, а разработчики перестают доверять их результатам.
Получается парадокс: компания вложилась в автоматизацию, чтобы выпускать продукты быстрее, а в итоге получила еще один сложный и дорогой слой инфраструктуры.
— Почему вообще возникла идея относиться к тестам как к отдельному продукту разработки? Разве их задача не сводится к тому, чтобы проверить программу и сообщить, есть в ней ошибка или нет?
— На небольшом проекте действительно может казаться, что тест — это просто сценарий, который один раз написали, запустили и получили результат. Но в крупном продукте тестовый код живет годами. Он развивается вместе с приложением, меняется вслед за новыми функциями, работает с данными и окружением, подключается к системе сборки и доставки обновлений. В какой-то момент это уже не набор отдельных проверок, а самостоятельная система, от которой напрямую зависит скорость разработки.
На практике я сталкивалась с ситуациями, когда именно отсутствие такого подхода постепенно становилось ограничением для команды. Сначала тестов становится больше, покрытие растет, а вместе с ним растет и количество вспомогательного кода. Но если архитектуру системы не продумывать заранее, любое изменение продукта начинает требовать изменений сразу в нескольких слоях тестовой инфраструктуры. В результате команда тратит время уже не на развитие продукта, а на обслуживание самих проверок.
И эта система тоже может ломаться. Если тесты нестабильны, непонятны или слишком сильно зависят друг от друга, команда постепенно перестает воспринимать их результаты как достоверный сигнал. Разработчик видит очередную ошибку при проверке и вместо того, чтобы искать проблему в своем изменении, думает: «Наверное, снова сломался тест». Это очень опасный момент, потому что автоматизация перестает выполнять свою главную функцию — давать команде уверенность в качестве продукта.
Поэтому к тестовому коду применимы практически те же требования, что и к основному: он должен быть понятным, структурированным, поддерживаемым, не содержать ненужной сложности и дублирования. Если мы относимся к тестам как к продукту, то начинаем их не просто писать, а проектировать.
— А что происходит с тестовой системой, если этого проектирования нет?
— Обычно первые несколько месяцев все выглядит хорошо. Команда быстро пишет проверки, процент покрытия растет, ошибки находятся, и кажется, что автоматизация развивается правильно. Проблемы становятся заметны позже, когда количество тестов увеличивается и продукт начинает активно меняться.
Проверки могут выполняться часами, часть из них начинает периодически падать без связи с реальными ошибками в продукте. Любое изменение приложения требует исправлять множество сценариев. Если попытаться запускать проверки одновременно, появляются конфликты из-за общих данных или зависимостей между тестами.
Я видела, как проблема постепенно превращалась в замкнутый круг: нестабильные тесты начинали падать, инженеры тратили время на выяснение причин, а затем часть проверок просто переставали учитывать при анализе результатов. Формально автоматизация продолжала работать, но ее практическая ценность снижалась.
Есть еще более серьезная проблема — организационная. Команда перестает доверять автоматизации и возвращается к ручным проверкам, потому что считает их надежнее. В результате компания вроде бы получила систему автоматического тестирования, но инженеры все равно тратят время на ручную работу. Получается ситуация, похожая на плохо спроектированную информационную систему: сначала она позволяет быстро двигаться, а затем каждое изменение становится все дороже.
— Можно ли сказать, что большое количество тестов само по себе ничего не гарантирует?
— Конечно. Количество проверок и даже высокий процент покрытия — далеко не единственные показатели качества. Можно иметь тысячи тестов и при этом не получать от них достаточной пользы.
Например, тест может проверять не реальное поведение системы, а взаимодействие с собственной заглушкой. Формально он проходит, но в рабочей среде система сталкивается с настоящим сервисом и ведет себя иначе. Получается ложное ощущение безопасности.
В крупных системах я бы вообще разделяла вопрос количества тестов и вопроса того, какие риски они действительно закрывают. Иногда десятки хорошо подобранных проверок дают больше пользы, чем сотни сценариев, которые формально увеличивают покрытие, но практически ничего не говорят о критичных для пользователя функциях.
Другой пример — нестабильные проверки. Если один и тот же тест сегодня проходит, завтра падает, а потом снова проходит без каких-либо изменений в продукте, команда вынуждена тратить время на выяснение причины. Постепенно такие ошибки начинают восприниматься как обычный информационный шум.
Поэтому я бы оценивала не только количество тестов, но и их стабильность, скорость выполнения, стоимость поддержки и способность находить реальные дефекты. Хорошая автоматизация должна экономить время инженеров, а не создавать для них новую постоянную работу.
— Тогда каким должен быть хороший тест?
— Прежде всего понятным. Любой инженер команды должен достаточно быстро разобраться, что именно проверяется, какие исходные данные используются и какой результат считается правильным.
Второе важное свойство — независимость. Тест не должен зависеть от того, какой сценарий выполнялся перед ним, какое состояние осталось после другого теста или какая запись сейчас находится в общей базе данных. Иначе при автоматическом запуске мы получим цепную реакцию: одна ошибка повлияет на несколько следующих проверок, и станет сложно понять, где находится настоящая проблема.
С этим особенно часто приходится сталкиваться при попытке ускорить выполнение большого набора проверок. Пока тесты запускаются последовательно, проблемы с общими данными могут быть незаметны. Но как только команда переходит к параллельному запуску, слабые места становятся очевидными: сценарии начинают конкурировать за одни и те же записи, учетные записи или состояние системы.
Третий принцип — не перегружать тест техническими деталями. Вспомогательные инструменты, модели, подготовка данных необходимы, но они должны скрывать сложность, а не переносить ее внутрь каждого сценария.
И еще один принцип — компактность. Тест должен оставаться прозрачным. Это не место, где нужно демонстрировать всю архитектурную мощь системы. Его задача — как можно яснее показать, что именно мы проверяем.
— Вы говорите о проектировании тестовой системы. Что это означает на практике? Что делает инженер до того, как написать первый тест?
— Сначала нужно определить, что именно мы хотим автоматизировать и какие риски закрыть. Не все части продукта одинаково важны и не все нужно проверять одним способом. Где-то достаточно проверки отдельного модуля, где-то необходимо проверить взаимодействие нескольких компонентов, а критические пользовательские сценарии требуют полноценной сквозной проверки.
Затем определяются требования к скорости выполнения, выбираются инструменты, продумывается структура самой системы: как будут создаваться данные, как организовать разные уровни проверок, каким образом результаты попадут в отчеты и систему сборки.
В моей практике именно на этом этапе часто становится понятно, будет ли автоматизация масштабироваться вместе с продуктом. Например, если заранее не определить правила подготовки данных и изоляции тестов, при увеличении их количества система неизбежно начинает сталкиваться с конфликтами. Если не продумать диагностику, каждое падение будет превращаться в отдельное расследование.
Очень важно заранее подумать о будущем. Продукт будет меняться, количество тестов будет расти. Поэтому нужно понимать, как добавлять новые сценарии, как изменять существующие, где будут точки расширения и каким образом инженеры будут искать причины ошибок.
Даже такие вещи, как единые правила именования, структура каталогов, журналирование событий и формат отчетов, на большом проекте становятся частью архитектуры. Когда тестов несколько тысяч, отсутствие единых правил уже невозможно компенсировать личной памятью отдельных специалистов.
— Но разве не получается, что такая подготовка замедляет разработку? Вместо того чтобы сразу писать проверки, команда тратит время на проектирование.
— В начале действительно кажется, что мы замедляемся. Нужно потратить время на выбор подхода, подготовить инфраструктуру, договориться о правилах. Но это инвестиция в последующую скорость.
Через несколько месяцев хорошо спроектированная система начинает возвращать вложенное время. Разработчик меняет код, запускает проверки и получает понятный результат. Если что-то сломалось, ему проще определить причину. Добавление новой функции не требует переписывать половину существующего набора тестов.
Это хорошо видно на больших проектах: когда тестовая инфраструктура изначально построена как набор разрозненных сценариев, ее развитие постепенно становится самостоятельной задачей. Когда же есть понятные уровни проверок, единые правила работы с данными и общие инструменты, добавление новых сценариев происходит значительно предсказуемее.
Кроме того, качественные тесты дают разработчикам свободу менять внутреннюю реализацию продукта. Если поведение системы зафиксировано надежными проверками, можно существенно перестроить код, не опасаясь незаметно нарушить существующую логику.
Поэтому проектирование тестовой системы — это не бюрократия ради бюрократии. В долгосрочной перспективе оно снижает стоимость изменений.
— Какие ошибки вы чаще всего встречаете, когда приходите на проект, где система автоматизации уже существует?
— Одна из самых распространенных — чрезмерно сложная обвязка. Иногда команда строит столько уровней абстракции, что спустя время уже трудно понять, где находится нужная логика. Кажется, что система очень архитектурно продуманная, но любое изменение продукта требует большого количества исправлений.
Вторая проблема — чрезмерная ставка на программные имитации. Они нужны и полезны в определенных случаях, но, если тест постоянно работает только с подмененными компонентами, он может не показать реальную проблему во взаимодействии систем.
Третья — отсутствие стратегии работы с данными. Например, несколько проверок используют одну учетную запись или одну запись в базе данных. Пока тесты выполняются последовательно, это может быть незаметно. Но при параллельном запуске они начинают мешать друг другу.
Еще одна проблема — плохая диагностика. Тест падает, а из отчета невозможно понять, что именно произошло и на каком этапе. Тогда инженер фактически начинает расследование с нуля. Чем крупнее система, тем дороже становится каждая такая ошибка.
— Почему именно тестовые данные становятся настолько серьезной проблемой?
— Потому что автоматизация предполагает повторяемость. Если результат теста зависит от того, какие данные случайно остались в системе, какая учетная запись уже использовалась или какой сейчас момент времени, мы теряем предсказуемость.
На одном из проектов именно работа с данными становилась критичной при масштабировании автоматизации. Отдельно взятый сценарий работал корректно, но при одновременном запуске нескольких проверок возникали конфликты: тесты обращались к одним и тем же данным и начинали влиять друг на друга. В результате падение одного сценария могло порождать ошибки в других, хотя сам продукт при этом работал корректно.
Представьте, что два теста одновременно пытаются изменить одну и ту же запись. Каждый из них отдельно проходит. Вместе они начинают влиять друг на друга, и результат становится случайным. В этом случае проблема не обязательно в самом продукте — она может находиться в организации тестового окружения.
Поэтому стратегию работы с данными нужно продумывать заранее. Данные должны быть изолированы настолько, насколько это необходимо для конкретного сценария, а сами тесты — по возможности независимы друг от друга.
— Сейчас много говорят о разработке через тестирование. Насколько этот подход связан с вашей идеей о том, что тесты нужно проектировать?
— Связь прямая. Разработка через тестирование показывает наиболее наглядный вариант отношения к тесту как к части проектирования. Когда инженер сначала описывает ожидаемое поведение системы в виде проверки, он фактически формулирует требования к будущему коду.
Модульные тесты в таком случае становятся не только способом найти ошибку, но и своеобразной документацией. Они показывают, что именно должна делать конкретная часть системы.
Это особенно полезно, когда код впоследствии меняется. Внутреннюю реализацию можно перестроить, но тесты позволяют проверить, сохранилось ли ожидаемое поведение.
При этом я бы не воспринимала разработку через тестирование как универсальный рецепт для любого проекта. Важнее другое: проверки должны оставаться актуальными, понятными, быстрыми и изолированными. Само наличие теста еще не делает систему надежной.
— А как убедить команду инвестировать в качество тестовой системы, если разработчики говорят: «У нас все работает»?
— Я бы не пыталась убеждать абстрактными рассуждениями о правильной архитектуре. Лучше показать стоимость конкретных проблем.
Сколько раз выпуск откладывался из-за нестабильных проверок? Сколько часов инженеры потратили на выяснение причин ложных ошибок? Сколько ручных проверок приходится выполнять несмотря на существующую автоматизацию? Сколько дефектов все-таки дошло до пользователей?
Когда эти показатели переводишь в конкретные затраты времени и денег, становится понятно, что тестовая система уже имеет стоимость. Вопрос только в том, приносит ли она пользу бизнесу.
В работе я стараюсь смотреть на автоматизацию именно через такую призму. Если команда тратит значительную часть времени на перезапуск тестов, разбор ложных падений или ручное восстановление данных, это уже не просто техническая проблема. Это потеря инженерного ресурса и скорости разработки.
После этого не обязательно предлагать полностью переписать систему. Гораздо реалистичнее начать с самых болезненных мест: стабилизировать критические проверки, разобраться с данными, улучшить отчеты, убрать ненужную сложность и постепенно вводить новые правила.
— А если система уже настолько запущена, что кажется проще начать все с нуля?
— Полностью остановить разработку и несколько месяцев переписывать тесты обычно невозможно. Поэтому я предпочитаю постепенную перестройку.
Сначала выделяется ядро наиболее важных проверок — тех, которым команда должна доверять в первую очередь. Их нужно сделать стабильными и понятными. Одновременно вводятся новые правила для всех новых тестов. Это важно: нельзя одновременно пытаться исправлять старый хаос и продолжать создавать новый по тем же принципам.
В одном из подобных сценариев именно такой подход позволяет не останавливать разработку: сначала стабилизируются проверки, которые дают наиболее важный сигнал о качестве продукта, затем постепенно перестраиваются общие компоненты, работа с данными и диагностика.
Затем система перестраивается постепенно: меняются общие заготовки, работа с данными, архитектура вспомогательных компонентов, разделяются зависимые сценарии.
При этом нужны измеримые показатели. Например, можно отслеживать долю нестабильных проверок, общее время выполнения, количество ложных ошибок и количество дефектов, которые автоматизация обнаружила до выхода продукта в рабочую среду.
Тогда перестройка становится не бесконечным ремонтом, а обычным инженерным процессом с понятным результатом.
— Если команда только начинает автоматизировать тестирование, какие решения стоит принять сразу, чтобы через несколько лет не пришлось все переделывать?
— Самое главное — с самого начала относиться к автоматизации как к разработке программного обеспечения. Нужны контроль изменений, проверка кода, понятные правила, ответственность за поддержку и понимание того, что тесты тоже могут содержать ошибки.
Второе — не пытаться сразу покрыть абсолютно все. Я бы начала с наиболее важных пользовательских сценариев и небольшого набора действительно надежных проверок. Лучше иметь меньше тестов, которым команда доверяет, чем огромное количество нестабильных сценариев.
Третье — заранее определить правила работы с данными, структуру проекта, требования к изоляции, журналированию и отчетности.
И четвертое — регулярно пересматривать тестовый набор. Продукт меняется, поэтому проверки тоже должны меняться. Старый сценарий, который больше не соответствует реальному поведению системы, не становится ценным только потому, что когда-то его написали. Иногда качественная автоматизация — это не добавление нового теста, а удаление ненужного.
— Получается, главная опасность заключается не в отсутствии автоматизации, а в ложном ощущении, что она уже решает проблему качества?
— Я бы сказала именно так. Само слово «автоматизация» создает ощущение, что мы один раз построили систему и дальше она будет самостоятельно обеспечивать качество. На самом деле это такой же живой компонент продукта, как и любой другой.
Тестовый код развивается, усложняется, устаревает, требует поддержки и архитектурных решений. Если этого не учитывать, он начинает работать против команды: замедляет выпуск изменений, создает ложные ошибки и отнимает инженерное время.
Мне близка формулировка «код для проверки кода», потому что она очень точно описывает суть. Если мы признаем, что тесты тоже являются программой, становится очевидно, что к ним должны применяться те же требования к качеству.
В конечном счете хорошая тестовая система нужна не ради самих тестов и не ради красивого процента покрытия. Ее задача гораздо практичнее — дать команде возможность быстрее развивать продукт и при этом понимать, что очередное изменение не превратится в проблему для пользователей. Именно в этом случае автоматизация действительно становится инструментом бизнеса, а не еще одной системой, которую разработчикам приходится обслуживать.
