Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

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

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

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

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

Спочатку трохи нудної теорії. Що таке автоматичне тестування? Це тестування, яке проводиться програмними засобами, і в сучасному IT воно все частіше використовується при розробці ПЗ. Пов'язано це з тим, що компанії зростають, зростають їхні інформаційні системи і відповідно зростає кількість функціоналу, яку треба тестувати. Проводити ручне тестування стає все більш накладним і накладним.

Я працював в одній великій компанії, релізи якої виходять раз на два місяці. При цьому цілий місяць витрачався на те, щоби десяток тестувальників руками перевіряли функціонал. Завдяки впровадженню автоматизації невеликою командою розробників нам удалося за півтора роки скоротити час тестування до 2 тижнів. Ми не лише збільшили швидкість тестування, а й підвищили його якість. Автоматичні тести запускаються регулярно і завжди виконують весь курс закладених у них перевірок, тобто ми виключаємо людський чинник.

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

Але що робити, якщо ваша система ґрунтується переважно на серверній логіці? Якогось універсального рішення та best practices на ринку не існує. Як правило, компанії вирішують цю проблему за рахунок створення власної самописної системи тестування. Ось така власна самописна система автоматизованого тестування була створена на нашому проекті і про неї розповім у своїй доповіді.

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

Тестуємо лояльність

Спочатку поговоримо про проект, де ми розгорнули систему автоматизованого тестування. Наш проект - це система лояльності Спортмайстра (до речі, ми вже писали про неї в цьому пості).

Якщо ваша компанія досить велика, то ваша система лояльності матиме три стандартні властивості:

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

Ходімо по порядку... У сукупності, якщо розглядати всі бренди Спортмайстра, то на території Росії, України, Китаю, Казахстану та Білорусі маємо понад 1000 магазинів. У цих магазинах щодня здійснюється близько 300 000 покупок. Тобто кожну секунду до нашої системи потрапляє 3-4 чеки. Звичайно, наша система лояльності є високонавантаженою. А коли нею активно користуються, ми повинні надавати найвищі стандарти її якості, адже будь-яка помилка в ПЗ — це великі грошові, репутаційні та інші втрати.

Водночас у Спортмайстрі працює понад сотня різних акцій. Акції різні: є товарні, є приурочені до дня тижня, є прив'язані до конкретного магазину, є акції на суму чека, є на кількість товарів. Загалом, не слабко. У клієнтів є бонуси, є промокоди, які використовуються при покупках. Все це призводить до того, що обрахунок будь-якого замовлення – це дуже нетривіальне завдання.

Алгоритм, що реалізує обробку замовлення, воістину страшний і складний. І будь-яке внесення змін до цього алгоритму – досить ризикована штука. Здавалося, були зовні незначні зміни, що можуть призводити до досить непередбачуваних ефектів. Адже саме такі складні обчислювальні процеси, які тим більше реалізують критичний функціонал, — найкращий кандидат на автоматизацію. Перевіряти руками десятки однотипних кейсів дуже дорого за часом. Оскільки точка входу в процес незмінна, то один раз описавши її, можна досить швидко наштампувати автоматичні тести і бути впевненим у роботі функціонала.

Так як нашою системою активно користуються, то бізнес хотітиме від вас чогось нового, житиме в ногу з часом і бути клієнтоорієнтованим. У нашій системі лояльності релізи виходять раз на два місяці. Отже, кожні два місяці нам потрібно проводити повний регрес усієї системи. При цьому, природно, як і в будь-якому сучасному IT, технологія не потрапляє відразу від розробника на продакшн. Вона зароджується на контурі розробника, потім послідовно пройде тестовий стенд, релізний, приймальний і лише потім виявляється на продакшені. Як мінімум на тестовому та на релізному контурах нам потрібно проводити повний регрес усієї системи.

Описані властивості є стандартними практично для будь-якої системи лояльності. Давайте поговоримо про особливості нашого проекту.

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

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

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

Враховуючи все вищесказане, для підвищення якості продукту, що видається, і зменшення термінів розробки, ідея автоматизації тестування на проекті здається досить логічною. І на різних етапах існування системи лояльності окремі розробники докладали зусиль, щоб покрити свій код юніт-тестами. Це загалом був досить розрізнений процес, де кожен використовував свою архітектуру та методи. Спільними для юніт-тестів були підсумкові результати: випробування розроблялися, якийсь час використовувалися, складалися у версійне сховище файлів, але рано чи пізно переставали запускатися і забувалися. Насамперед це відбувалося з того, що тести були прив'язані більше до конкретного виконавця, а не до проекту.

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

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

Знаєте щось про Стівена Фейєрштейна?

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

Давайте подивимося на прикладі, як виглядає код unit-тесту, реалізований за цією методикою.

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

Отже, на екрані подано код типової специфікації пакета з unit-тестами. Які обов'язкові вимоги? Пакет повинен мати префікс utp_. Такий самий префікс повинні мати всі процедури з тестами. У пакеті обов'язково повинні бути дві стандартні процедури: «utp_setup» і «utp_teardown». Перша процедура викликається перезапуск кожного unit-тесту, друга - після запуску.

"utp_setup", як правило, готує нашу систему до запуску unit-тесту, наприклад створює тестові дані. "utp_teardown" - навпаки, все повертає до вихідних налаштувань і скидає результати запуску.

Ось приклад найпростішого unit-тесту, який перевіряє нормалізацію введеного номера телефону клієнта до стандартного для нашої системи лояльності. Якихось обов'язкових стандартів, як писати процедури з unit-тестами, немає. Як правило, здійснюється виклик будь-якого методу системи, що тестується, і результат, повернутий даним методом, порівнюється з еталонним. Важливо, щоб порівняння еталонного результату та отриманим відбувалося через стандартні utPLSQL-ні методи.

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

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

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

Ось так unit-тести запускаються. Допустимо два варіанти запуску: запуск усіх юніт-тестів із конкретного пакету або запуск конкретного юніт-тесту в конкретному пакеті.

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

Ось так виглядає приклад внутрішньої системи звітності. За результатами роботи юніт-тесту utPLSQL будує невеликий звіт. У ньому ми бачимо результат щодо кожної конкретної перевірки та загальний результат виконання юніт-тесту.

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

Перед тим як розпочинати створення нової системи автоматизованого тестування системи лояльності, спільно з керівництвом ми визначили принципи, яким наші майбутні автотести повинні відповідати.

Unit-тести у СУБД — як ми робимо це у Спортмайстрі, частина перша

  1. Автотести мають бути ефективними та повинні приносити користь. У нас чудові розробники, про які обов'язково треба сказати, адже хтось із них, напевно, побачить цю доповідь, і вони пишуть чудовий код. Але навіть їхній чудовий код не є ідеальним і містив, містить і міститиме помилки. Автотести повинні ці помилки шукати. Якщо це не так, то ми пишемо погані автотести, або ми прийшли в мертву область, яка в принципі не допрацьовується. В обох випадках ми робимо щось не так, і наш підхід просто безглуздий.
  2. Автотести повинні використовуватись. Безглуздо витратити купу часу та сил на написання програмного продукту, скласти його репозитарій та забути. Тести повинні запускатися і запускатися якомога регулярніше.
  3. Автотести мають працювати стабільно. Незалежно від часу доби, стенду запуску та інших налаштувань системи, запуски тестів повинні призводити до того самого результату. Як правило, це забезпечується тим, що автотести працюють із спеціальними тестовими даними із зафіксованими налаштуваннями системи.
  4. Автотести повинні працювати з прийнятною для вашого проекту швидкістю. Цей час визначається індивідуально кожної системи. Хтось може собі дозволити працювати цілий день, а комусь критично вкладатись у секунди. Яких швидкісних нормативів ми досягли в нашому проекті, я розповім трохи згодом.
  5. Розробка автотестів має бути гнучкою. Небажано відмовлятися від перевірки будь-якого функціоналу просто тому, що ми так ще не робили або з якихось інших переконань. utPLSQL не накладає жодних обмежень на розробку, а Oracle в принципі дозволяє реалізовувати різні речі. Більшість завдань має рішення, питання лише у часі та витрачених зусиллях.
  6. Розгортання. У нас кілька стендів, де потрібний запуск тестів. На кожному зі стендів у будь-який момент може бути оновлено дамп із даними. Потрібно вести проект з автотестами таким чином, щоб мати можливість безболісно робити його повну або часткову установку.

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

Джерело: habr.com

Додати коментар або відгук