Автоматизація тестування: як уникнути поширених помилок | GlobalLogic Ukraine

Автоматизація тестування: як уникнути поширених помилок

Ярослав Пернеровський

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

Бути чи не бути

Вам гарантовано потрібна автоматизація тестування, якщо:

  • У вас проект тривалістю в рік або більше. Кількість тестів, які потрібно проганяти в рамках регресії, стрімко зростає, а рутину потрібно викорінювати в першу чергу. Тестувальники повинні тестувати, а не проходити тест-кейси.
  • У вас розподілена команда розробки або в команді більше двох розробників. Розробник повинен бути впевнений, що його зміни не зламають чужий код. Без авто-тестів він дізнається про це в кращому випадку через день-два, в гіршому — від користувачів.
  • Ви підтримуєте кілька версій продукту і випускаєте патчі й сервіспаки під кожну з них. Тут все зрозуміло: тестування на різних конфігураціях — це рутина, а її треба викорінювати.
  • Ви розробляєте сервіс, основне завдання якого — обробка і трансформація різних даних. Займатися ручним вбивання даних у систему і візуальним аналізом результатів або відправкою запитів і аналізом відповідей — це взагалі не те, чим повинні займатися живі люди кожен день.
  • У вас аджайл з короткими ітераціями і частими релізами. Часу на ручний прогін регресії в рамках спринту катастрофічно не вистачає, а знати, що все в порядку в тих місцях куди не лазили тестувальники, необхідно.

Якщо ваш проект не такий, то вам швидше за все не треба забивати голову думками про автоматизацію.

Навіщо взагалі потрібні авто-тести

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

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

Чому очікування не виправдовуються

Існує досить багато причин, через які автоматизація може не виправдати сподівань. І всі вони у той чи інший спосіб пов’язані з невірно прийнятими рішеннями в інженерній чи управлінській областях, а іноді і в обох одночасно.

Управлінські рішення — це тема для окремої статті, а поки я просто підкреслю найважливіші помилки без пояснень:

  • Спроба заощадити на фахівцях в області автоматизації. Якщо менеджер вважає, що він може відправити своїх тестувальників на курси з Selenium, і вони йому зроблять автоматизацію, то він неправий.
  • Спроба впровадити автоматизацію без чітко продуманої стратегії і планування, типу «Давайте будемо впроваджувати, а там подивимося». Або ще гірше — автоматизація заради автоматизації: «У сусіда є, і мені потрібно; навіщо — незрозуміло, але потрібно».
  • Занадто пізній старт: тести починають автоматизувати тільки тоді, коли тестувальники вже зовсім загинаються.
  • Переконання, що дешевше найняти студентів, які будуть клікати регресію руками (тобто взагалі не робити автоматизацію, хоча наявні всі ознаки проекту, якому вона потрібна).

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

Розглянемо деякі моменти з інженерної точки зору.

Чому автоматизація тільки UI-тестів — зло

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

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

— UI-тести нестабільні;

— UI-тести повільні.

Нестабільні вони тому, що тести залежать від «верстки» інтерфейсу додатку. При зміні порядку розташування кнопок на екрані або додаванні/видаленні якогось елементу тести можуть зламатися. Інструмент автоматизації не зможе знайти потрібний елемент або натисне абсолютно не ту кнопку, і логіка тесту зміниться.

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

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

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

Що ж робити

Стабілізуємо. Насправді, я навмисне перебільшив проблему нестабільності, тому що розв’язати її нескладно, але часто автоматизатори навіть не намагаються її вирішити.

Перше, що потрібно зробити в будь-якому випадку — це домовитися з розробниками, щоб вони не забували прописувати для елементів унікальні атрибути, за якими інструмент автоматизації може їх точно ідентифікувати. Тобто потрібно максимально відмовитися від п’ятиповерхових xPath-виразів або CSS-селекторів і, по можливості, всюди використовувати унікальні id, name і т.п. Це повинно бути чітко прописано в девелопмент-гайдах і виступати одним з пунктів в definition of done для розробників. Тоді навіть у випадку капітальних перетворень користувацького інтерфейсу у вас є шанс відбутися легким переляком.

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

Додаток, що тестується повинен давати можливість себе протестувати. Якщо такої можливості немає, то додаток потрібно або модифікувати, або викинути.

Крім того, не зайвим буде навчити інструмент автоматизації чекати зручного моменту, коли елемент стає доступним для взаємодії або спочатку використовувати щось типу Selenide, де такої проблеми немає by design.

Прискорюємося. Якщо з нестабільністю все досить просто, то проблема повільних тестів повинна вирішуватися комплексно, оскільки вона впливає на процес розробки в цілому.

Перше і найпростіше, що може прискорити процес, — деплоїти додаток і запускати тести на більш «швидкому» залізі, уникати ситуацій, коли на взаємодію тесту і додатку впливають затримки мережі і т.п. Тобто «вирішити» проблему за рахунок заліза і архітектури тестового стенду. Вже це може дати істотну економію за часом, у два чи більше разів.

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

Третє і найрадикальніше — створювати якомога менше UI-тестів. Менше тестів — раніше отримуємо результат їх прогону.

Піраміда тестування

Всі пам’ятають відому піраміду тестування?

QA Pyramide Pernerovsky Blo

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

Тут все просто. Згадаймо, як зазвичай виглядає процес знаходження і виправлення проблеми в додатку, коли його тестують вручну. Спочатку розробник вносить нові зміни в код. Тестувальник чекає збірку і деплой нового білда на тестовий стенд. Тестувальник проводить тестування, знаходить проблему і заводить тікет в баг-трекінговій системі. Розробник моментально реагує на цей тікет і виправляє проблему. Це нові зміни в код, і потім знову білд, деплой, ретест. Якщо все ок — тікет закривається. Час від виявлення проблеми до її виправлення становить від декількох годин до декількох діб або навіть тижнів.

Що відбувається, коли той же тест автоматизований через UI? Так само треба чекати, поки збереться і задеплоїться нова версія, потім чекати, поки завершаться тести. Потім треба проаналізувати результати прогону. Якщо були проблеми — визначити, де ці проблеми виникли: в самому тесті або в додатку. Потім потрібно ще раз прогнати тест, що впав, руками, щоб напевно зрозуміти, в чому проблема. Завести тікет, почекати поки його пофіксять, перезапустити тест, переконатися, що тепер тест зелений, закрити тікет. Знову ж — від кількох годин до кількох днів/тижнів. Плюс тільки в тому, що цей тест автоматичний, і поки він працює, тестувальник тестує щось інше.

Інша історія, коли є автоматизовані тести, які використовують API для спілкування з бек-ендом додатки. Тут вже є цікаві варіанти:

  • Тести ганяються на повністю задеплоєному додатку з усіма зовнішніми системами. У порівнянні з чистими UI-тестами сильно скорочується час виконання та аналізу результатів, оскільки тут набагато менше хибно-позитивних спрацьовувань. Все інше так само, як і в UI-тестах.
  • Тести після складання білда, але без деплою на тестовий стенд; використовуються заглушки для зовнішніх систем. Тести запускаються в контексті збірки білда, знайдені проблеми часто не вимагають створення тікетів, тому що запуск проводиться розробником, який робить зміни в коді, і одразу ж їх фіксить. Тут виграш у швидкості між виявленням і виправленням проблеми просто величезний.
  • Ну, і звичайно ж «вершки» — це юніт- і компонентні авто-тести. Вони не вимагають збірки всього проекту, запускаються відразу після компіляції модуля без виходу з улюбленої IDEшки, відгук — миттєвий. Час від внесення змін до виправлення можливих проблем вимірюється в хвилинах.

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

Комплексний підхід

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

UI-тести тестують цілісну систему, а саме — те, що буде використовувати користувач. Критично важливо мати такі тести в наявності.

Загальна рекомендація тут одна: потрібно мати всі види авто-тестів в потрібній кількості на кожному з рівнів. Тоді з’являється можливість отримувати ефективну віддачу від таких тестів.

Test Driven Development — це вже навіть не рекомендація, це повинно йти від розробника за замовчуванням. Тільки тоді можна уникнути труднощів під час рефакторингу і типових проблем розробки у великих командах.

На рівень API-тестів потрібно опускати всі функціональні тести, які тестувальники проводили протягом спринту. Негативні, позитивні, комбінаторні і т.п. Таким чином створюється швидкий і стабільний пакет регресійних тестів.

На рівень UI-тестів виносяться виключно приймальні тести, так звані Happy Path або End-To-End сценарії, які показуються під час демо. Це стосується як веб-, так і мобільних додатків.

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

Резюме

Не на всіх проектах є потреба у повноцінній автоматизації: деяким може вистачити допоміжних скриптів для полегшення життя тестувальників. Але коли ми маємо справу з проектом, який розвивається і розвиватиметься довго, в якому задіяно багато людей і є повноцінний відділ тестування, то без автоматизації там не обійтися.

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

Ярослав Пернеровський,  Quality Assurance Consultant, GlobalLogic

Thank You.

The white paper will open in a new window.

If you experience issues with accessing or downloading the white paper, please contact info@globallogic.com.

click here to go back to the Insights page.