Мікросервісна архітектура вже давно є стандартом у розробці. Тож QA-фахівцям потрібно знати відмінності у підходах до тестування таких продуктів у порівнянні з тими, що мають монолітну основу. Детально про це — в огляді від експертів ІТ-команди NIX.
У чому різниця між монолітами та мікросервісами
Вибір моделі розробки софту залежить від особливостей конкретного проєкту. В деяких випадках переваги мікросервісів не настільки критичні, щоб перекрити плюси моноліту. Тому обидва підходи залишаються актуальними.
QA-спеціалістам слід вміти працювати з обома архітектурами. Перш ніж перейти до підходів у тестуванні, згадаймо, що являють собою мікросервіси та моноліти.
Монолітна архітектура — традиційна модель розробки програмного забезпечення, з єдиним модулем, який працює незалежно від інших.
Часто слово «моноліт» використовують для позначення чогось великого і незграбного. Ці слова досить добре описують монолітну архітектуру з погляду розробників. Така архітектура призводить до створення великої, незалежної мережі серверів зі спільною кодовою базою, яка поєднує всі бізнес-задачі. Бодай одна зміна в такому продукті вимагає оновлення продукту цілком, що забирає багато часу та зусиль команди.
Мікросервісна архітектура — принципово інший спосіб організації системи. В її основі — сервіси, що розгортаються незалежно один від одного. Вони мають власні бізнес-логіку і бази даних для окремих цілей. Оновлення, тестування і масштабування відбуваються всередині сервісів.
Сьогодні це один із найочевидніших варіантів при розробці застосунків. На мікросервісах будують нові продукти і «переїжджають» чимало старих проєктів. Це пояснюється прискоренням темпів розробки, гнучкістю процесів і легкістю масштабування.
Принцип роботи мікросервісів чудово поєднується з CI/CD-моделлю та DevOps-практиками й дозволяє швидко адаптуватися до вимог користувачів.
Як тестувати мікросервіси
У продукті з мікросервісною архітектурою кожен мікросервіс виконує певну функцію: авторизує користувача, відповідає за інтеграцію із платіжним або картографічним сервісами, обробляє замовлення тощо. Коли вони поєднуються, фактично й створюється повноцінний продукт для вирішення певного завдання.
Мікросервіси можуть писати на різних мовах та використовувати в основі різні технології. Інколи це ускладнює схему взаємозв’язків між сервісами. Тому чи не головною проблемою у їхньому тестуванні може стати низька база знань тестувальників.
Тестування мікросервісів розділяють на кілька рівнів.
Unit-тестування
Потрібно написати тести для кожного методу (функції). При виконанні тесту це дасть якомога більший рівень покриття логіки застосунку. Так уже на ранній стадії розробки ви знайдете початкові баги за найменших витрат та ризиків для проєкту. Покриття такими тестами допомагає визначити, чи не призвели зміни коду до помилок. Але для цього юніт-тести мають бути інтегровані в CI-процеси, щоб команда оперативно отримувала фідбеки.
Unit-тестування монолітної та мікросервісної архітектури має такі відмінності:
- Об’єкт тестування. При тестуванні монолітів тестовим об’єктом є вся кодова база з усім функціоналом застосунку. У мікросервісах тестування сфокусоване на кожному сервісі.
- Налагодження тестів. У моноліті всі компоненти знаходяться в одному застосунку, тому юніт-тестування прямолінійне та досить просте. А от у мікросервісах кожен окремий сервіс вимагає ізоляції під час тестування від усієї системи. Загалом це ускладнює роботу.
- Робота з залежностями. В мікросервісній архітектурі кожен сервіс можна тестувати окремо від інших, що спрощує юніт-тестування. А в моноліті всі компоненти мають пряму залежність один від одного, тому їх важче ізолювати для такого типу тестів. Це ускладнює логіку тестів або систему керування моками.
- Розгортання. В монолітах розробка та деплой застосунку зазвичай відбуваються разом. Юніт-тестування є централізованим та інтегрованим. У мікросервісів кожен елемент має свій цикл розробки. Тму QA зосереджені на юніт-тестуванні своєї частини і не чіпають інші.
Функціональне тестування на рівні сервісу
У застосунках з монолітною архітектурою функціональність зазвичай об’єднана в одному блоці. Тоді тестування направлене на перевірку основних функцій та взаємодій усередині програми. Через те, що розробка та розгортання застосунку відбуваються разом, функціональне тестування може бути частиною цього процесу.
У випадку ж мікросервісної архітектури таке тестування включає перевірку функцій кожної частини окремо. Мета тестів — підтвердити, що компоненти правильно виконують завдання та обробляють дані. Тестові сценарії повинні базуватися на вимогах та очікуваній поведінці конкретного сервісу.
Також врахуйте, що в мікросервісній архітектурі всі компоненти можуть функціонувати на різних фізичних або віртуальних машинах і мати різні тестові оточення. Для функціонального тестування можуть знадобитись окремі інструменти. Наприклад, для створення заглушок чи симуляції зовнішніх сервісів у тестових оточеннях.
Функціональне тестування мікросервісів вимагає ізоляції тестованих компонентів та перевірки того, що кожен сервіс працює коректно. Тому створюйте тестові оточення, які максимально точно відтворюють умови роботи окремих мікросервісів. Так ви забезпечите однорідні умови для кожного тестового запуску.
Проста локалізація проблем та відсутність масштабного ретестінгу при внесенні змін до системи — беззаперечні плюси в тестуванні мікросервісів. Адже всі зміни будуть обмежені ретестестуванням самого сервісу та його контрактів.
Контрактне тестування
У мікросервісах з’являється такий вид тестів як контрактні тести. Причина цьому — мережеві взаємодії між сервісами системи. Тож вам потрібно проводити ще й перевірку контрактів API. Контрактне тестування стає важливим інструментом забезпечення сумісності та узгодженості між версіями сервісів. При внесенні змін до контрактів API або взаємодії між сервісами необхідно перевірити, що все відбувається без збоїв.
Тестування контрактів гарантує, що дві сторони здатні взаємодіяти одна з одною. Споживач фіксує зв’язок із постачальником та створює контракт, який є специфікацією запитів від споживача та відповідей від постачальника. Для такого типу тестів можна використовувати фреймворк Pact. Він перевіряє зв’язок між споживачем та постачальниками за протоколом HTTP.
Інтеграційне тестування
Має підтвердити, що інтерфейси мікросервісів розроблені правильно і всі незалежні компоненти працюють як єдине ціле. Для цього зовнішні залежності, які не є об’єктами тестування в конкретному випадку, можна замінити заглушками або моками. Самі ж об’єкти перевірки мають залишитись без змін, щоб переконатися в правильності їх взаємодії.
Інтеграційне тестування моноліту може бути складнішим. Вам необхідно перевірити велику кількість шляхів виконання застосунку та взаємодій. Також тут важливо забезпечити консистентність і валідність тестових даних. Наприклад, це можуть бути попередньо налаштовані тестові дані або ті, що ви створили в процесі тестування.
Е2Е-тестування
На цьому рівні не дуже помітна різниця між тестуванням монолітної та мікросервісної архітектур. Еnd-to-end тести передбачають повну інтеграцію — або всіх мікросервісів, які створюють цілісну систему, або всього застосунку-моноліту.
Як моки допомагають при тестуванні мікросервісів
Використання моків дуже пошире при тестуванні застосунків із мікросервісною архітектурою. Це пов’язано з тим, що компоненти системи розділені на окремі служби, які взаємодіють через мережеві виклики або API. Мікросервіси часто залежать від зовнішніх служб або компонентів (баз даних, черг повідомлень, сторонніх API тощо). Моки дозволяють ізолювати від залежностей окремий сервіс, що тестується. З’являється контрольоване середовище для тестування, що дозволяє створювати стабільніші тести.
Що варто знати при роботі з моками:
- Тестові двійники. Цим терміном позначають різні техніки:
Моки. Імітують поведінку реальних об’єктів або компонентів, з якими взаємодіє код. Моки надають відповіді на виклики методів і можуть бути налаштовані для перевірки правильності взаємодії з ними. Зазвичай такі двійники використовують для тестування взаємодії між компонентами системи.
Фейки. Ці реалізації залежностей замінюють реальні компоненти та сервіси з коду. У фейків зазвичай спрощена реалізація, яка може відрізнятись від реальної поведінки, але це дозволяє виконувати тести. Наприклад, фейкова БД може зберігати дані в пам’яті, а не в постійному сховищі.
Заглушки. Замінюють реальні реалізації та повертають заздалегідь визначені значення. Їх часто використовуються для ізоляції коду від зовнішніх залежностей та емуляції конкретних сценаріїв або умов проведення тестів.
Шпигуни. Ці об’єкти відстежують та записують інформацію про взаємодію коду, який тестується, з його залежностями. Дозволяють перевіряти виклики методів, передані параметри та значення, що повертаються, для аналізу та перевірки в тестах.
- Манкі-патчинг. Техніка програмування, що дозволяє змінювати або розширювати поведінку наявного коду під час виконання застосунку без його прямої модифікації.
- Проксі та інтерсептори. Використовуються для перехоплення та зміни поведінки об’єктів або систем. Тут варто окремо сказати про ці складові:
Проксі — це об’єкт, що виступає як проміжна ланка між клієнтом і цільовим об’єктом. Він перехоплює виклики та може втручатися у їхню обробку. Проксі забезпечує додатковий рівень абстракції та контролю доступу до цільового об’єкта та може використовуватися для різних цілей: обмеження доступу, кешування, логування, керування транзакціями тощо.
Інтерсептори — перехоплюють та обробляють виклики до об’єктів чи методів у системі. З ними можна втручатися у виклики до, після або під час їхнього виконання. Ви зможете модифікувати поведінку системи, додавати функції та забезпечувати гнучку, контрольовану розробку ПЗ.
- Мок-сервіси. Це імітації або замінники реальних сервісів та компонентів, що використовуються для тестування й розробки застосунків. Мок-сервіси допомагають ізолювати код від реальних залежностей і створити контрольоване середовище. Зазвичай для цього використовують особливі фреймворки або спеціальні інструменти. Ви отримуєте API або інтерфейс, схожий на реальний сервіс. Так ваш код буде взаємодіяти без зв’язку з реальним сервісом або зовнішніми ресурсами (базами даних, мережевими сервісами, сторонніми API). Це спрощує розробку та забезпечує надійність і швидкість тестів.
Архітектура продукту впливає на вибір стратегії тестування
Моноліти завдяки цілісній структурі дозволяють легко налаштовувати тестові середовища та проводити E2E-тестування всього застосунку. Водночас розширення моноліту ускладнює його підтримку та тестування, оскільки будь-яка зміна може вимагати ретестування всього продукту.
Мікросервісні застосунки розподілені на менші, автономні сервіси. Це дозволяє локалізувати зміни та зменшити обсяг ретестування. Однак тестування таких систем потребує налаштування складних тестових середовищ, які відтворюють взаємодію між сервісами.
Окреме місце у тестуванні мікросервісів займає створення моків та керування ними. Вони допомагають ізолювати сервіси та гнучкого керувати їхнім станом.
Маючи загальне уявлення про структуру тестових об'єктів, вам буде простіше обрати відповідні підходи та інструменти для тестування. Тоді і перевірки будуть цілеспрямовані. Розуміння архітектури дозволяє розробляти ефективні стратегії тестування. А це вже ваш внесок у якість, надійність та безпеку продукту.
Редакція не несе відповідальності за інформацію, викладену у блогах. Це особиста думка автора.
Підписуйтеся на ProIT у Telegram, щоб не пропустити жодної публікації!