Первая часть — здесь.
Представьте ситуацию. Перед вами стоит задача разработки нового функционала. У вас есть наработки от ваших предшественников. Если предположить, что вы никаких моральных обязательств не имеете, то как бы вы поступили?
Чаще всего все старые наработки подвергаются забвению и всё начинается сначала. В чужом коде копаться никто не любит, а при наличии времени почему бы не заняться созданием собственной системы? Это типичный подход, и он во многом правильный. Но в своём проекте мы поступили не так. В основу будущей системы автоматического тестирования мы заложили наработки по unit-тестам на utPLSQL от предшественников, а затем пошли работать в нескольких параллельных направлениях.
- Восстановление старых unit-тестов. Под восстановлением понимается адаптация тестов под существующее состояние системы лояльности и адаптация тестов под стандарты utPLSQL.
- Решение проблемы с пониманием, а что именно, какие методы и процессы, у нас покрыты автотестами. Надо либо эту информацию держать в голове, либо делать выводы на основании непосредственно кода автотестов. Поэтому мы решили сформировать каталог. Каждому автотесту мы присвоили уникальный мнемокод, сформировали описание и зафиксировали настройки (например, в каких условиях он должен запускаться, или что должно происходить, если запуск теста завершился неудачей). По сути, мы заполнили метаданные об автотестах и поместили эти метаданные в стандартные таблицы схемы utPLSQL.
- Определение стратегии расширения, т.е. выбор функционала, который подлежит проверке автотестами. Мы решили обратить внимание на три вещи: новые доработки системы, инциденты с продакшена и ключевые процессы системы. Таким образом, мы развиваемся параллельно с релизом, обеспечивая более высокое его качество, попутно расширяем объем регресса и обеспечиваем надежность системы в критичных местах. Первым таким узким местом стал процесс распределения скидок и бонусов по чеку.
- Естественно, мы занялись разработкой новых автотестов. Одной из первых релизных задач стала оценка производительности предопределённых выборок системы лояльности. В нашем проекте есть блок жестко зафиксированных sql-запросов, которые отбирают клиентов по условиям. Например, получить список всех клиентов, последняя покупка которых была в конкретном городе, или список клиентов, средняя сумма покупки которых выше определенного значения. Написав автотесты, мы проверили предопределённые выборки, зафиксировали эталонные параметры производительности, а дополнительно у нас появились нагрузочное тестирование.
- Работа с автотестами должна быть удобной. Наиболее часто совершаются два действия: запуск автотестов и создание тестовых данных. Так в нашей системе появились два вспомогательных модуля: модуль запуска и модуль генерации данных.
Модуль запуска представлен в виде одной универсальной процедуры с одним входным текстовым параметром. В качестве параметра можно передавать мнемокод автотеста, название пакета, название теста, настройку автотеста или зарезервированное ключевое слово. Процедура отбирает и запускает все автотесты, удовлетворяющие условиям.
Модуль генерации данных представлен в виде пакета, в котором для каждого объекта тестируемой системы (таблица в БД), создана специальная процедура, которая вставляет туда данные. В данной процедуре максимально заполнены дефолтные значения, что обеспечивает создание объектов буквально по щелчку пальцев. И для удобства использования были созданы шаблоны создаваемых данных. Например, создать клиента определённого возраста с тестовым телефоном и совершённой покупкой.
- Автотесты должны запускаться и работать за приемлемое для вашей системы время. Поэтому был организован ежедневный ночной запуск, по результатам которого формируется отчёт о результатах и рассылается всей команде разработки по корпоративной почте. После восстановления старых автотестов и создания новых общее время работы составляло 30 минут. Подобная производительность всех устраивала, так как запуск проходил во внерабочее время.
Но над оптимизацией скорости работы пришлось поработать. Обновление системы лояльности на продакшене производится ночью. В рамках одного из релизов ночью пришлось экстренно вносить изменения. Получасовое ожидание результатов автотестов в три часа ночи не сделало ответственного за релиз счастливым (пламенный привет Алексею Васюкову!), а на следующее утро в сторону нашей системы было сказано много теплых слов. Но по итогам был установлен 5-минутный норматив на работу.
Для ускорения производительности мы воспользовались двумя методами: автотесты стали запускаться в трех параллельных потоках, благо это очень удобно из-за архитектуры нашей системы лояльности. И мы отказались от подхода, когда автотест не создает для себя тестовые данные, а пытается найти в системе что-то подходящее. После внесения изменений общее время работы сократилось до 3-4 минут.
- Проект с автотестами надо мочь разворачивать на различных стендах. В начале пути были попытки написать собственные батники, но стало понятно, что самописная автоматизированная установка — это полный ужас, и мы обратились в сторону промышленных решений. В связи с тем, что в проекте очень много непосредственно кода (в первую очередь мы храним код автотестов) и очень мало данных (основные данные — это метаданные об автотестах), то очень простым оказалось внедрение в проект Liquibase.
Это независимая от базы данных библиотека с открытым исходным кодом для отслеживания, управления и применения изменений схемы базы данных. Управляется посредством командной строки или фреймворков типа Apache Maven. Принцип работы Liquibase достаточно прост. У нас есть организованный определенным образом проект, который состоит из изменений или скриптов, которые надо накатывать на целевой сервер, и управляющие файлы, которые определяют, в какой последовательности и с какими параметрами данные изменения надо устанавливать.
На уровне СУБД создаётся специальная таблица, в которой Liquibase хранит лог накатов. Каждое изменение имеет рассчитанный хэш, который каждый раз сравнивается между проектом и состоянием в базе. Благодаря Liquibase мы легко накатываем изменения нашей системы на любой контур. Автотесты сейчас запускаются на тестовом и релизном контурах, а также на контейнерах (личных контурах разработчиков).
Итак, давайте поговорим о результатах применения нашей системы unit-тестирования.
- Конечно же, в первую очередь, мы убеждены, что начали разрабатывать более качественное ПО. Автотесты запускаются ежедневно и ежерелизно находят десятки ошибок. Притом часть этих ошибок лишь косвенно связана с функционалом, который мы реально хотели поменять. Есть большие сомнения, что эти ошибки были найдены ручным тестированием.
- У команды появилась уверенность, что конкретный функционал работает корректно… В первую очередь это касается наших критичных процессов. Например, за последние полгода у нас не было проблем с распределением скидок и бонусов по чеку, несмотря на ежерелизные изменения, хотя в предыдущие периоды с некоторой периодичностью ошибки возникали
- Нам удалось сократить количество итераций тестирования. Благодаря тому, что автотесты пишутся на новый функционал, к аналитикам и по совместительству тестировщикам попадает код более высокого качества, т.к. он уже был проверен.
- Часть наработок автоматизированного тестирования используется разработчиками. Например, тестовые данные на контейнерах создаются с помощью модуля генерации объектов.
- Немаловажно, что у нас сложилось «принятие» системы автоматизированного тестирования со стороны разработчиков. Есть понимание, что это важно и полезно. А по своему опыту могу сказать, что это далеко не так. Автотесты надо писать, их надо поддерживать и развивать, анализировать результаты, а часто эти временные затраты просто того не стоят. Намного проще сходить на продакшн и там разбираться с проблемами. У нас же разработчики выстраиваются в очередь и просят покрыть их функционал автотестами.
Что дальше
Давайте поговорим о планах развития проекта по автоматизированному тестированию.
Безусловно, пока система лояльности Спортмастера жива и продолжает развиваться, можно также практически бесконечно развивать автотесты. Поэтому основное направление развития – это расширение зоны покрытия.
По мере увеличении количества автотестов неуклонно будет расти общее время их работы, и нам вновь придётся вернуться к вопросу производительности. Скорее всего, решение будет в увеличении количества параллельных потоков.
Но это очевидные пути развития. Если говорить о чём-то более нетривиальном, выделим следующее:
- Сейчас управление автотестами выполняется на уровне СУБД, т.е. нужны знания PL/SQL для успешной работы. По необходимости управление системой (например, осуществление запусков или создание метаданных) можно вынести какую-то админку, использовав Jenkins или что-то аналогичное.
- Все любят количественные и качественные показатели. Для автоматического тестирования таким универсальным показателем является Code Coverage или метрика покрытия кода. При помощи данного показателя мы можем определить, какой процент кода нашей тестируемой системы покрывается автотестами. Начиная с версии 12.2 Oracle предоставляет возможности по расчету данной метрики и предлагает использовать стандартный пакет DBMS_PLSQL_CODE_COVERAGE.
Нашей системе автотестирования чуть больше года и, возможно, сейчас самое время для оценки покрытия. В моём прошлом проекте (проект не Спортмастера) так и получилось. Спустя год после работы над автотестами руководство поставило задачу оценить, каков процент кода мы покрываем. При покрытии более 1% руководство было бы счастливо. Мы, разработчики, ожидали результат около 10%. Прикрутили code coverage, замерили, получили 20%. На радостях отправились за премией, но как мы за ней сходили и куда направились позже, это совсем другая история.
- Автотесты могут проверять выставленные веб-сервисы. Oracle вполне позволяет это делать, а мы больше не встретим целый ряд проблем.
- И, естественно, нашу систему автоматизированного тестирования можно применить на другом проекте. Полученное нами решение является универсальным и всего лишь требует использования Oracle. Я слышал, что на других проектах Спортмастера есть заинтересованность в автоматическом тестировании и, возможно, мы отправимся к ним.
Выводы
Давайте подытожим. На проекте система лояльности в Спортмастере нам удалось реализовать систему автоматизированного тестирования. Базисом её является решение utPLSQL от Стивена Фейерштейна. Вокруг utPLSQL расположен код автотестов и вспомогательные самописные модули: модуль запуска, модуль генерации данных и другие. Автотесты ежедневно запускаются и, что самое важное, работают и приносят пользу. Мы убеждены, что начали выпускать ПО более высокого качества. При этом полученное решение универсально и может быть свободно применено на любом проекте, где необходимо организовать автоматизированное тестирование на СУБД Оракл.
P.S. Данная статья получилась не очень конкретной: здесь много текста и практически отсутствуют технические примеры. Если глобально тематика интересна, то мы готовы её продолжить и вернуться с продолжением, где расскажем, что изменилось за прошедшие полгода и привести примеры кода.
Пишите комментарии, если есть моменты, на которых стоит сделать акцент в будущем, или вопросы, требующие раскрытия.
Автор: Максим Пономаренко