Генерування юніт-тестів з використанням машинного навчання



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

Ключові слова--юніт-тест, машинне навчання, нейронні мережі, генератор, тренування моделі.

Вступ

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

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

Методи автоматизованого генерування юніт-тестів

Для досягнення високої ефективності набору тестів існує багато різних підходів. Деякими з них є:

  • Рандомізоване тестування. Базовий та прямолінійний підхід, який складається з виклику функцій з випадковими вхідними даними [1].
  • Тестування, основане на пошуку. Алгоритми пошуку, або генетичні алгоритми, перетворюють задачі генерування юніт-тестів у проблеми оптимізації, де ціль генерування тестів реалізована через функцію допасованості, яка керує пошуком [2].
  • Символічне тестування. Символічний підхід представляє шляхи виконання через програму як обмеження, встановлене на вхідних значеннях. Найбільш відомим є динамічне символічне виконання (Dynamic Symbolic Execution) [3].

Існує багато алгоритмів машинного навчання з нейронними мережами, які можуть перекладати послідовності. Для даного дослідження були обрані sequence-to-sequence (seq2seq) нейронні мережі [4], основані на рекурентних нейронних мережах [5] або згорткових нейронних мережах [6], тому що вони можуть швидко оброблювати довгі послідовності з високою точністю.

Аналіз існуючих рішень

Найпопулярнішими існуючими рішеннями для генерування юніт-тестів для мови програмування Java є EvoSuite, Randoop та Symbolic PathFinder [7]. EvoSuite є відкритим програмним забезпеченням, створеним за методом тестування пошуком, та використовує еволюційний підхід, оснований на генетичному алгоритмі, для генерування юніт-тестів з метою задоволення критерію покриття. Randoop використовує рандомізоване тестування, направлене на зворотній зв’язок. Symbolic PathFinder є прикладом інструменту на основі символічного тестування, який комбінує символічне виконання з перевіркою моделі та рішенням обмежень. Головними недоліками вищеперерахованих підходів є складність читання та розуміння згенерованих тестів, які виглядають як машинний код. Також дані інструменти мають такі недоліки, як незадовільні якість коду та вміння виявлення помилок. Дані рішення переважно фокусуються на покритті коду, ігноруючи інші фактори, які можуть бути важливими для розробників.

Структурна схема системи генерування юніт-тестів

Модуль збору даних знаходить відкрите програмне забезпечення за певними фільтрами, наприклад, усі проекти мають використовувати одну і ту же мову програмування та один і той же фреймворк юніт-тестування. Далі до зібраного та проаналізованого програмного коду застосовується алгоритм пов’язання юніт-тестів до вихідного коду, завдяки якому створюються пари з методів юніт-тестів та методів вихідного коду, які тестуються. Ці тест-пари поділяються на тренувальний сет, який використовується для тренування моделі машинного навчання; валідаційний сет, який дозволяє визначити, коли необхідно припинити тренування; та верифікаційний сет для оцінки та порівняння моделі. Потім починається етап тренування. Процес тренування завершується валідацією для впевнення, що подальше тренування не вплине негативно на результат, зменшуючи можливість узагальнення. Врешті-решт, модель проходить процес верифікації, використовуючи верифікаційний сет, який складається з даних, до яких модель не є оптимізованою. В результаті отримуємо модель, готову до передбачення тестів. В подальшому модель можна використовувати для генерування юніт-тестів, передаючи їй у якості вхідних даних вихідний код проекту без юніт-тестів. Описаний процес зображений на рис. 1.

Рис. 1 Структурна схема системи генерування юніт-тестів

Алгоритм пов’язання коду до тестів

Для тренування алгоритму машинного навчання необхідні тренувальні приклади. Щоб створити їх, необхідний набір даних з пар, які складаються з методів вихідного коду та юніт-тестів. Однак, не існує прямого зв'язку між тестом та кодом, який тестується. Таким чином, щоб мати змогу створити пари, необхідний алгоритм пов’язання юніт-тестів з методами.

Спочатку необхідно знайти у проектах класи, які містять у собі тест-кейси. Це можна зробити за допомогою анотації @Test для мови програмування Java та фреймворку тестування JUnit. Якщо клас містить хоча б один метод з анотацією @Test, його можна назвати тестовим класом.

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

  • Пошук за шляхом. Взявши за основу стандартну структуру організації пакетів в Java-проектах, почнемо пошук вихідного коду з кореневого каталогу (src/main/java), шлях якого має відповідати тестовим класам у кореневому каталозі (src/test/java).
  • Пошук за назвою. За загальноприйнятою згодою щодо оформлення коду, назва тестового класу зазвичай складається з назви класу, що тестується, з префіксом або суфіксом “Test”.

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

Висновки

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

Література

{1} Arcuri A. Random testing: Theoretical results and practical implications / A. Arcuri, M. Iqbal, L. Briand., 2012. – 277 с.

{2} McMinn P. Search-Based Software Test Data Generation: A Survey / Phil McMinn., 2004. – 156 с.

{3} https://en.wikipedia.org/wiki/Symbolic\\_execution (дата звернення 04.11)

{4} https://www.analyticsvidhya.com/blog/2020/08/a\-simple\-introduction\-to\-sequence\-to\-sequence\-models (дата звернення 05.11.2021)

{5} https://www.ibm.com/cloud/learn/recurrent\-neural\-networks (дата звернення 05.11.2021).

{6} https://en.wikipedia.org/wiki/Convolutional\\_neural\\_network (дата звернення 06.11.2021).

{7} https://knapsackpro.com/testing\\_frameworks/ difference\_between/evosuite/vs/randoop-net (дата звернення 09.11.2021).

Dec 5, 2021