Привет, привет!
Пару лет назад было решено поделиться историей про автоматизированное тестирование СУБД и наш опыт применения в Спортмастере. С результатами можно ознакомиться здесь и здесь.
И сейчас, спустя значительное время, хочется подвести итоги и порефлексировать о системе. Да и даже просто ответить на вопрос: «Как там ваши автотесты?»
Спойлер
Краткое описание предыдущих частей
Есть система лояльности Спортмастера:
огромная, сложная и высоконагруженная система 24/7
важный функционал для бизнеса
активно развивается
есть сложные вычислительные алгоритмы
много потребителей
система преимущественно содержит серверную логику на Oracle
Хотелось повысить качество выпускаемого продукта и сократить время на тестирование, поэтому внедрили систему автоматизированного тестирования на PL/SQL:
ядро системы – это open source библиотека utPLSQL v 2.3 от Стивена Фейерштейна
вокруг utPLSQL развёрнуты самописные модули, которые облегчают работу с автотестами:
модуль запуска автотестов
модуль генерации тестовых данных
модуль управления метаданными
модуль отчётности
и т.д.
сформирован каталог автотестов с определением ключевых настроек
автоматизированы запуск автотестов, отчётность и накат изменений
А что же сейчас?
Самое важное, что стоит сказать про систему автоматизированного тестирования – она успешно работает, приносит пользу и постоянно развивается. А каждая ошибка, найденная автотестом, приводит примерно к такому состоянию:
Но это всё демагогия, поэтому перейдём к качественным показателям:
Количество автотестов: ?2400
Время работы полного запуска: ?40 секунд
Показатель Code Coverage: ?55%
Скорость работы
Одним из ключевых параметров системы автоматизированного тестирования является время работы автотестов. В каких-то системах всегда запускаются все тесты, а в каких-то выделяется определённая группа тестов и принимается решение, что такого запуска достаточно для уверенности в работоспособности. Но так или иначе со скоростью работы сталкиваются все, а уж всем автоматизаторам веба и тем более древних приложений я совсем не завидую (отдельный привет TestComplete!).
Автоматизация тестирования на уровне СУБД позволяет избежать большого числа проблем, связанных со внешней средой, но для быстрой работы тестов всё равно необходимо немного пошаманить.
Изначально, наши автотесты работали порядка 30 минут. Небольшое погружение в сторону параллельного запуска позволило сократить общее время работы до 5 минут, но и на этом мы не остановились. Для достижения текущего эталонного результата в 40 секунд было сделано:
Разбиение всех автотестов на логические функциональные блоки
Обеспечение изолированности тестовых данных под каждый функциональный блок автотестов
Каждый функциональный блок должен работать с персональными тестовыми данными. По окончанию теста система возвращается в исходное состояние.
Иногда возврат системы в исходное состояние невозможен или слишком трудоёмок. В этом случае автотест должен работать на данных, которые не мешают работе остальной системе и не блокируют следующий запуск автотеста или параллельную работу автотестов. Например, в уникальные ключи тестовых объектов можно зашивать код автотеста и текущую дату и время.
Запуск каждого функционального блока в отдельном потоке
Формирование сводной отчётности по полному запуску автотестов
Code Coverage
Я всегда с большой улыбкой относился к метрикам покрытия кода, потому что они, конечно, что-то говорят про вашу систему и автотесты, но вот что именно – не очень понятно. При этом идеал в 100%-ное покрытие практически недостижим. А даже если и достижим, то никак не гарантирует, что в системе ошибок нет.
А при тестировании серверной части всё становится ещё более непонятно. Ведь работа системы зависит от данных в таблицах. Есть sql-запросы, которые в принципе не поддаются анализу по покрытию. И разве хоть какая-то метрика может дать адекватную оценку состоянию автотестов?
Но так как вопросы про покрытие задаются слишком часто, пришлось внедрять в систему автоматического тестирования code coverage, благо что Oracle, начиная с версии 12.2, подобный функционал предоставляет.
Это оказалось совсем несложным:
перед запуском автотестов вызвать: dbms_plsql_code_coverage.start_coverage
выключить функционал по окончанию всех работ: dbms_plsql_code_coverage.stop_coverage
написать запрос, который считает покрытие
А мы, получив приятную цифру в 50% покрытие, пошли заниматься более интересными вещами.
Автоматическая генерация кода
Наращивание количества автотестов – это простая и понятная задача. Были бы ресурсы, а автотесты всегда появятся. Но, конечно же, хочется сократить издержки на выпуск автотестов. А самый быстрый способ написания кода – не писать код совсем!
В какой-то момент стало понятно, что большинство автотестов крайне похожи друг на друга, и мы начали думать в сторону автоматической генерации кода. Требовалось указывать конкретный метод системы, подлежащий покрытию автотестом, а на выходе получать полностью валидный код, отформатированный согласно стандартам отдела разработки.
Автоматически сгенерённый код должен содержать:
Инициализацию всех входных и выходных переменных простых типов
Инициализацию всех входных и выходных коллекций
Процедуры для сравнения двух коллекций одного типа
Вызов тестируемого метода
Базовые проверки выходных значений
Хотелось бы конечно, чтобы автотесты начали разрабатываться полностью сами, но с чего-то начинать надо? Реализовав описанное решение, мы стали экономить лишние 10-15 минут при создании каждого автотеста. Дополнительно, автоматическая генерация кода оказалась очень полезной в процессе адаптации новых сотрудников на проекте.
utPLSQL v3
В качестве базиса системы автоматизированного тестирования используется utPLSQL v2, в то время как уже очень давно вышла 3-я версия фреймворка и именно она продолжает активно развиваться. Стоит отметить, что utPLSQL v3 - это фундаментальная переработка старого решения с реализацией нового и классного функционала.
Так почему же у нас в проекте используется более старая версия фреймворка? К сожалению, utPLSQL v 3 не поддерживает несколько важных для нас фич. Что-то разработчикам кажется концептуально неправильным, до чего-то не доходят руки. Все проблемы решаемы, благо что код библиотеки так и остался открытым и может быть самостоятельно изменён. Соответствующая задача в техническом долге заведена, но она не является наиболее приоритетной в нашей дорожной карте развития автотестов.
Заключение
На проекте лояльности Спортмастера уже несколько лет успешно работает система автоматизированного тестирования на PL/SQL. Основные показатели системы и некоторые технические решения освещены в данной статье. Но мы не останавливаемся в развитии и помимо планового расширения покрытия постоянно находим новые вызовы.
Было бы очень интересно узнать, с какими проблемами вы сталкивались при реализации автотестирования и какие решения находите.
Всем добра!
granvi
Ни слова конкретики.
Я вот много лет рабоиал с разной сложности информационными системами. И Мне вот чисто гипотетически интересно, как можно за 30 секунд пройти все бизнес процессы в "сложно связанной системе".
Пару примеров не помешало бы
mrhawk555 Автор
Приму к сведению и пройдёмся по примерам в следующих выпусках
granvi
Вот я не знаю, что именно вы вклпдываете в термин "юнит тесты"… Я не предсиавляю, как можно за указанное время, да даже просто пересобрать пакет или создать набор фейковой схемы БД с тестовым набором данных (если это не запросы вида SELECT TRUE FROM DUAL. Проверку процедур и функций на валидность? Так это делает сама субд на этапе компиляции. Непротиворечивость? Так это опять делает сама СУБД средствами ограничейний целостности.
За 30 секунд не любой коммит то пройдёт… А как вы тестируете оптимизацию в гипер-больших отношениях? Как анализируется оптимальность семаниисеской модели? Наличие, правильность и оптимальность создания индексных структур, ключей, триггеров и вообще процесса нормализации и контролируемой избыточности?
Как и где выводятся метрики планов запросов в тестируемых пакетах на данных разного размера? А как тестируется связи с внешними систеиами?
И тд и тп… Это самые основные задачи в разработке СУБД. а то, что вы тестируете за 30 секунд. Это шляпа какая то и попахивает профанацией.
И ладно бы, но это как с масками сейчас. По рекомендации ВОЗ их нужно носить только больным, так как они дают ложное ощущение защиты.
Так и у вас. Эти ваши юнит тесты дабт ложное ощущение контроля и можно проморгать большой пипец.
dimuska139
Любое тестирование подразумевает под собой какие-либо компромиссы. Где-то нужно обращение к внешнему сервису «замокать», где-то ещё что-то. Особенно если речь идёт о юнит-тестах, где тестируются изолированно по сути отдельные функции. То есть «тестируете оптимизацию в гипер-больших отношениях», «как тестируется связи с внешними системами» — это вообще не про юнит-тесты.
Я так понял, исходя из текста статьи и того, что её автор пишет в комментариях, что:
Если много логики сделано в виде хранимых процедур, то почему бы это не покрыть тестами?