Хабрахабр

Unit-тесты в СУБД — как мы делаем это в Спортмастере, часть первая

Привет, Хабр!

Имею 10-летний опыт работы в IT-сфере. Меня зовут Максим Пономаренко и я — разработчик в Спортмастере. Последние 4 года, аккумулируя знания, полученные в тестировании и разработке, занимаюсь автоматизацией тестирования на уровне СУБД. Начинал карьеру в в области ручного тестирования, затем переключился на разработку баз данных.

В апреле мы с ребятами из Sportmaster Lab выступали на конференции в Краснодаре, мой доклад назывался «Unit-тесты в СУБД», и сейчас хочу поделиться им с вами. В команде Спортмастера я состою чуть более года и на одном из крупных проектов занимаюсь разработкой автоматизированного тестирования. В первом мы поговорим об автотестах и тестировании в общем, а во втором я подробнее остановлюсь на нашей системе unit-тестирования и результатах ее применения. Текста будет много, поэтому я решил разбить доклад на два поста.

Что такое автоматическое тестирование? Вначале немного скучной теории. Связано это с тем, что компании растут, растут их информационные системы и соответственно растет и количество функционала, которое надо тестировать. Это тестирование, которое проводится программными средствами, и в современном IT оно все чаще и чаще используется при разработке ПО. При этом целый месяц тратился на то, чтобы десяток тестировщиков руками проверяли функционал. Проводить ручное тестирование становится всё накладнее и накладнее.
Я работал в одной крупной компании, релизы которой выходят раз в два месяца. Мы не только увеличили скорость тестирования, но и повысили его качество. Благодаря внедрению автоматизации небольшой командой разработчиков нам удалось за полтора года сократить время тестирования до 2 недель. Автоматические тесты запускаются регулярно и они всегда выполняют весь курс заложенных в них проверок, то есть мы исключаем человеческий фактор.

Для современного IT характерен тот факт, что от разработчика может требоваться не только писать код продукта, но писать unit-тесты, которые данный код проверяют.

Какого-то универсального решения и best practices на рынке не существует. Но что делать, если ваша система основывается преимущественно на серверной логике? Вот такая собственная самописная система автоматизированного тестирования была создана на нашем проекте и о ней я расскажу в своем докладе. Как правило, компании решают эту проблему за счет создания собственной самописной системы тестирования.

Тестируем лояльность

Для начала поговорим о проекте, где мы развернули систему автоматизированного тестирования. Наш проект — это система лояльности Спортмастера (кстати, мы уже писали про нее в этом посте).

Если ваша компания достаточно крупна, то ваша система лояльности будет обладать тремя стандартными свойствами:

  • Ваша система будет высоконагруженной
  • Ваша система будет содержать сложные вычислительные процессы
  • Ваша система будет активно дорабатываться.

Пойдём по порядку… В совокупности, если рассматривать все бренды Спортмастера, то на территории России, Украины, Китая, Казахстана и Беларуси у нас более 1000 магазинов. В этих магазинах ежедневно осуществляется около 300 000 покупок. То есть каждую секунду в нашу систему попадает 3-4 чека. Естественно, наша система лояльности является высоконагруженной. А раз ею активно пользуются, мы должны предоставлять самые высокие стандарты ее качества, ведь любая ошибка в ПО — это большие денежные, репутационные и прочие потери.

Акции самые разные: есть товарные, есть приуроченные ко дню недели, есть привязанные к конкретному магазину, есть акции на сумму чека, есть на количество товаров. Одновременно в Спортмастере работает более сотни разных акций. У клиентов есть бонусы, есть промокоды, которые используются при покупках. В общем, неслабо. Все это приводит к тому, что обсчет любого заказа — это весьма нетривиальная задача.

И любое внесение изменений в этот алгоритм — довольно рискованная штука. Алгоритм, реализующий обработку заказа, воистину ужасен и сложен. А ведь именно такие сложные вычислительные процессы, тем более реализующие критичный функционал — лучший кандидат на автоматизацию. Казалось был самые внешне незначительные изменения, могут приводить к достаточно непредсказуемым эффектам. А так как точка входа в процесс неизменна, то один раз описав её, можно достаточно быстро наштамповать автоматические тесты и быть уверенным в работе функционала. Проверять руками десятки однотипных кейсов очень накладно по времени.

В нашей системе лояльности релизы выходят раз в два месяца. Так как нашей системой активно пользуются, то бизнес будет хотеть от вас чего-то нового, жить в ногу со временем и быть клиентоориентированным. При этом, естественно, как и в любом современном IT, разработка не попадает сразу от разработчика на продакшн. Значит, каждые два месяца нам нужно проводить полный регресс всей системы. Как минимум на тестовом и на релизном контурах нам нужно проводить полный регресс всей системы. Она зарождается на контуре разработчика, затем последовательно минует тестовый стенд, релизный, приемочный и только потом оказывается на продакшене.

Давайте поговорим об особенностях нашего проекта. Описанные свойства являются стандартными для практически любой системы лояльности.

Есть выставленный клиент на Delphi, который выполняет функцию АРМ-администратора. Технологически на 90% логика нашей системы лояльности серверная и реализована на Oracle. Поэтому весьма логично, что если мы будем разворачивать систему автоматизированного тестирования, то будем делать это на Oracle. Есть выставленные веб-сервисы для внешних приложений (например веб-сайт).

Но за последний год наша команда сильно увеличилась, и теперь над проектом трудятся 10 человек. Система лояльности в Спортмастере существует более 7 лет и создавалась единичными разработчиками… Среднее количество разработчиков на нашем проекте в течение этих 7 лет составляло 3-4 человека. И есть повышенный риск того, что мы будем пропускать ошибки. То есть в проект приходят люди, которые не знакомы с типовыми задачами, процессами, архитектурой.

Тестирование, безусловно, есть, но тестированием занимаются аналитики, помимо своих прочих основных обязанностей: по общению с бизнес-заказчиками, пользователями, проработкой требований к системе и т.д. Для проекта характерно отсутствие выделенных тестировщиков как штатных единиц. и т.п… Несмотря на то, что тестирование проводится очень качественно (особенно это уместно упомянуть, так как кому-то из аналитиков может попасться на глаза этот доклад), эффективность специализации и концентрации на чем-то одном никто не отменял.

И на разных этапах существования системы лояльности отдельные разработчики предпринимали усилия, чтобы покрыть свой код юнит-тестами. Учитывая всё вышесказанное, для повышения качества выдаваемого продукта и уменьшения сроков разработки, идея автоматизации тестирования на проекте кажется весьма логичной. Общими для юнит-тестов были итоговое результаты: тесты разрабатывались, какое-то время использовались, складывались в версионное хранилище файлов, но в какой-то момент переставали запускаться и забывались. Это в целом был достаточно разрозненный процесс, где каждый использовал свою архитектуру и методы. В первую очередь это происходило по тому, что тесты были привязаны больше к конкретному исполнителю, а не проекту.

На помощь приходит utPLSQL

Знаете что-нибудь про Стивена Фейерштейна?

Одна известная его книга так и называется: «Oracle PL/SQL. Это умный дядька, который длительную часть своей карьеры посвятил работе с Oracle и с PL/SQL, написал на эту тему достаточно большое количество трудов. Именно Стивену принадлежит разработка решения utPLSQL, или, как оно расшифровывается, Unit Testing framework for Oracle PL/SQL. Для профессионалов». На момент доклада последняя версия датируется 24 мартом 2019 года.
Что же это такое. Решение utPLSQL было создано в 2016 году, но над ним продолжают активно работать и выпускать новые версии. Весит пару мегабайт с учётом примеров и документации. Это отдельный опенсорный проект. Установка занимает несколько секунд. Физически представляет собой отдельную схему в базе данных ORACLE с набором пакетов и таблиц для организации юнит-тестирования. Помимо запуска в utPLSQL хранится лог всех ваших тестовых запусков, а также есть внутренняя система отчётности. Отличительной особенностью utPLSQL является простота эксплуатации.
Глобально, utPLSQL представляет собой механизм для запуска юнит-тестов, где под юнит-тестом понимаются обычные оракловые пакетные процедуры, организация которых соответствует некоторым правилам.

Давайте посмотрим на примере, как выглядит код unit-теста, реализованный по данной методике.

Какие есть обязательные требования? Итак, на экране представлен код типовой спецификации пакета с unit-тестами. Точно такой же префикс должны иметь все процедуры с тестами. Пакет должен иметь префикс «utp_». Первая процедура вызывается перезапуском каждого unit-теста, вторая — после запуска. В пакете в обязательном порядке должны присутствовать две стандартные процедуры: «utp_setup» и «utp_teardown».

«utp_teardown» — наоборот, все возвращает к исходным настройкам и сбрасывает результаты запуска. «utp_setup», как правило, подготавливает нашу систему к запуску unit-теста, например, создает тестовые данные.

Каких-то обязательных стандартов, как писать процедуры с unit-тестами, нет. Вот пример самого простого unit-теста, который проверяет нормализацию введенного номера телефона клиента к стандартному для нашей системы лояльности виду. Важно, чтобы сравнение эталонного результата и полученным происходило через стандартные utPLSQL-ные методы. Как правило, осуществляется вызов какого-либо метода тестируемой системы, и результат, возвращенный данным методом, сравнивается с эталонным.

Как видно из примера, мы делаем четыре последовательных вызова тестируемого метода по нормализации номера телефона и после каждого вызова оцениваем результат. В юнит-тесте может быть любое количество проверок. При разработке юнит-теста надо учитывать, что существуют проверки, которые никак на систему не влияют, а после некоторых надо откатываться к исходному состоянию системы.
Например, в представленном юнит-тесте мы просто форматируем входной номер телефона, что никак на систему лояльности не влияет.

А если мы пишем юнит-тесты по методу создания нового клиента, то после каждой проверки в системе будет создан новый клиент, что может влиять на последующий запуск теста.

Допустимо два варианта запуска: запуск всех юнит-тестов из конкретного пакета или запуск конкретного юнит-теста в конкретном пакете. Вот так unit-тесты запускаются.

По результатам работы юнит-теста utPLSQL строит маленький отчёт. Вот так выглядит пример внутренней системы отчетности. В нём мы видим результат по каждой конкретной проверке и общий результат выполнения юнит-теста.

6 правил автотестов

Перед тем как приступать к созданию новой системы автоматизированного тестирования системы лояльности, совместно с руководством мы определили принципы, которым наши будущие автотесты должны соответствовать.

  1. Автотесты должны быть эффективными и должны приносить пользу. У нас замечательные разработчики, о которых обязательно надо сказать, ведь кто-то из них наверняка увидит этот доклад, и они пишут замечательный код. Но даже их замечательный код не является идеальным и содержал, содержит и будет содержать ошибки. Автотесты обязаны эти ошибки находить. Если это не так, то либо мы пишем плохие автотесты, либо мы пришли в мертвую область, которая в принципе не дорабатывается. В обоих случаях мы делаем что-то не так, и наш подход просто бессмысленный.
  2. Автотесты должны использоваться. Бессмысленно потратить кучу времени и сил на написание программного продукта, сложить его репозитарий и забыть. Тесты должны запускаться, и запускаться как можно регулярнее.
  3. Автотесты должны работать стабильно. Вне зависимости от времени суток, стенда запуска и прочих настроек системы, запуски тестов должны приводить к одному и тому же результату. Как правило, это обеспечивается тем, что автотесты работают со специальными тестовыми данными с зафиксированными настройками системы.
  4. Автотесты должны работать с приемлемой для вашего проекта скоростью. Данное время определяется индивидуально для каждой системы. Кто-то может себе позволить работать целый день, а кому-то критично укладываться в секунды. Каких скоростных нормативов мы добились в нашем проекте, я расскажу чуть позже.
  5. Разработка автотестов должна быть гибкой. Нежелательно отказываться от проверки какого-либо функционала просто потому, что мы так ещё не делали или по каким-то другим убеждениям. utPLSQL не накладывает никаких ограничений на разработку, а Oracle в принципе позволяет реализовывать самые разные вещи. Большинство задач имеет решение, вопрос только во времени и потраченных усилиях.
  6. Развёртываемость. У нас несколько стендов, где нужен запуск тестов. На каждом из стендов в любой момент может быть обновлён дамп с данными. Нужно вести проект с автотестами таким образом, чтобы иметь возможность безболезненно производить его полную или частичную установку.

А во втором посте через пару дней я расскажу, что мы сделали и каких результатов добились.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть