Как стать автором
Обновить
127.31
SimbirSoft
Лидер в разработке современных ИТ-решений на заказ

ИИ в тестировании ПО: возможности, ограничения, эксперименты и практический опыт

Уровень сложностиПростой
Время на прочтение28 мин
Количество просмотров265

Вот уже пару лет чат-боты, основанные на больших языковых моделях, «гремят» на весь интернет. Поражают своими возможностями и делают то, о чем около 15 лет назад можно было услышать только в фантастических сюжетах. При этом важно что, сейчас Large Language Model (LLM) дошли до широкого круга потребителей и все могут их увидеть и протестировать. В связи с этим возникают дискуссии, размышления, статьи-прогнозы на тему того, как искусственный интеллект (ИИ) изменит рынок труда, кого заменят, сократят, а кто останется и т.д. Профессия QA и процессы тестирования тоже не остались без подобных рассуждений. 

Привет, Хабр! Меня зовут Андрей, я QA-специалист в компании SimbirSoft. В этой статье хочу поделиться опытом и впечатлениями моих коллег в использовании ИИ для рабочих задач.

Содержание статьи:

Введение

Применение ИИ в анализе ТЗ и создании тестов

Анализ ошибок и локализация багов

Создание отчетности о тестировании

ИИ в автоматизации тестирования (написании автотестов)

Заключение

Если сильно упростить работу QA, то получится следующее:

  • Анализ требований (ТЗ) и создание тестов

  • Выполнение тестирования

  • Локализация багов

  • Отчетность о тестировании

  • Работы по автоматизации тестирования  

Мы не будем рассматривать пункт «Выполнение тестирования» в его прямой формулировке, поскольку выполнить тесты можно автоматизированным или ручным способом. Написанию автотестов посвятим отдельный блок, а по ИИ-инструментам, которые заменяют ручное тестирование консистентных результатов, пока опыта не набралось :)

Таким образом, можно выделить следующие сферы, в которых рассмотрим применение ИИ:

  • Анализ ТЗ и написание тестовой документации

  • Анализ ошибок и локализация багов

  • Создание отчетности о тестировании

  • ИИ в автоматизации тестирования (написании автотестов)

Перед началом основной части статьи хочется обозначить некоторые моменты:

  • В данном материале понятия «ИИ», «Нейросеть»,  «LLM», «Языковая модель», «GPT», «бот» и т.д. предлагаю считать синонимами. Да, это не совсем корректно, но это и не научная статья, а скорее обзорная :)

  • Механики обучения, работы, формирования ответа ИИ рассматривать подробно и отдельно не будем, так как на эту тему уже есть много отличных материалов.

  • Практический опыт будет представлен в виде работы с «собирательным образом» ИИ, но с учетом того, какой именно GPT-бот применялся.

Применение ИИ в анализе ТЗ и создании тестов

Начнем с классики – того, что считается одной из трудоемких работ QA-специалиста — написание тестовой документации (ТД). Что нужно, чтобы создать тесты? Прочитать требования (ТЗ). Писать тестовую документацию долго и трудно, особенно, если это тест-кейсы, а не чек-листы. Чем сложнее и объемнее функционал, тем объемнее нужна документация. Поэтому от ее создания часто отказываются или сильно сокращают этот этап. И часто впоследствии возникают проблемы, связанные с падением качества ПО — общеизвестный факт в профессиональной среде QA.

Но писать ТД надо. Правильная тестовая документация приносит больше пользы, чем издержек. В конце концов, тестирование ПО — та же программа и методика испытаний (ПМИ), только в IT, а любая ПМИ предполагает список проверок, а также порядок их проведения.

Итак, мы определили, что писать тестовую документацию все же придется. Здесь напрашивается очевидное решение — отправить в нейросеть ТЗ и попросить написать тест-кейсы (или чек-листы).

Вот как описывает свой опыт Ирина, QA-специалист SimbirSoft: 

Было необходимо очень быстро написать чек-листы и тест-кейсы на всю функциональность, поскольку предыдущий тестировщик этим не занимался. Чтобы ускорить процесс, я отправляла ТЗ частями и писала свой запрос ИИ. В итоге тестовая документация получалась очень скудной и «джуновской», никакую конкретику чат не дал. Все равно пришлось все руками писать.

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

Если очень кратко, то в моем случае нужно было написать следующее: «Ты тестировщик бэкенда с опытом работы 5 лет, тебе необходимо сделать то и то. Если будут уточняющие вопросы, задавай». Так чат должен был понять, какого уровня ему выдавать ответы.

Кроме того, я использовала чат для написания мок-заглушек на Groovy. Ни одна заглушка без ошибок не прошла. Более того, она была составлена некорректно.

Я пробовала задать чату вопросы, на которые заранее знала ответ, понимая, что он не всегда отвечает со 100% точностью. Поэтому, на мой взгляд, он еще не настолько хорош в доступных версиях, чтобы его использовать в работе по вопросам, в которых сам кое-как разбираешься.

Сразу следует уточнить важное: отправлять в GPT-боты ТЗ, код и другие реальные артефакты строго не рекомендуется, поскольку, во-первых, таким  образом, вы 100% нарушаете NDA, во-вторых, снижаете безопасность проекта (закрытая информация утекает во внешние системы). 

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

Но есть другой вариант — попросить нейросеть написать проверки для некой абстрактной страницы, формы, сущности.

Вот что получалось с разной периодичностью обращения к Chat GPT:

Запрос пользователя: 

Напиши 3 тест-кейса для проверки формы регистрации

Ответ чата GPT:

Тест кейсы для формы регистрации:

1.  Проверка обязательных полей:

* Описание:  Проверить, что форма не позволяет отправить данные без заполнения обязательных полей (например, имя, пароль, email).

* Шаги:

    1.  Открыть форму регистрации.

    2.  Оставить одно или несколько обязательных полей пустыми.

    3.  Попытаться отправить форму.

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

* Ожидаемый результат: Форма не должна быть отправлена, и должно быть выведено сообщение об ошибке, указывающее на незаполненные обязательные поля.

2.  Проверка валидации email:

* Описание: Проверить, что форма валидирует email адрес пользователя, чтобы он был в правильном формате.

* Шаги:

    1.  Открыть форму регистрации.

    2.  В поле email ввести некорректный адрес, например, без символа "@" или с неправильным доменом.

    3.  Попытаться отправить форму.

    4.  Проверить, выводится ли сообщение об ошибке, указывающее на некорректный формат email.

* Ожидаемый результат: Форма не должна быть отправлена, и должно быть выведено сообщение об ошибке, указывающее на некорректный формат email.

3.  Проверка пароля на соответствие требованиям:

* Описание: Проверить, что форма валидирует пароль пользователя, чтобы он соответствовал установленным требованиям (например, минимальная длина, наличие цифр и специальных символов).

* Шаги:

    1.  Открыть форму регистрации.

    2.  В поле пароль ввести пароль, не соответствующий требованиям (например, слишком короткий, без цифр).

    3.  Попытаться отправить форму.

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

* Ожидаемый результат: Форма не должна быть отправлена, и должно быть выведено сообщение об ошибке, указывающее на несоответствие пароля требованиям.

Все адекватно — классические проверки начала тестирования.

Что если попросить написать более сложные кейсы? 

Запрос пользователя: 

Напиши 3 более сложных тест-кейса для проверки формы регистрации

Ответ чата GPT:

Более сложные тест кейсы для проверки формы регистрации:

1.  Проверка обработки ошибок при невалидных данных:

* Описание: Проверить, как форма реагирует на ввод невалидных данных, например, очень длинных строк, символов, не относящихся к  языку ввода,  и  др. 

* Шаги:

    1.  Открыть форму регистрации.

    2.  Ввести невалидные данные в различные поля формы, например:

        * В поле "Имя" -  ввести  очень  длинную  строку,  символы  не  из  латиницы  или  кириллицы,  специальные  символы.

        * В поле "Email" -  ввести  адрес  с  некорректным  форматом  или  несуществующим  доменом.

        * В поле "Пароль" - ввести  очень  короткий  пароль,  пароль  без  цифр,  пароль  без  специальных  символов,  пароль  с  одинаковыми  символами.

    3.  Попытаться отправить форму.

    4.  Проверить, выводится ли сообщение об ошибке, корректно ли оно  сформулировано  и  указывают  ли  ошибки  на  конкретную  проблему  в  введенных  данных.

    5.  Проверить,  что  форма  не  отправляется  с  невалидными  данными  и  остается  в  том  же  состоянии,  что  и  до  отправки  (например,  не  перенаправляется  на  другую  страницу).

* Ожидаемый результат: 

    * Форма не должна быть отправлена с невалидными данными.

    * Должно быть выведено сообщение об ошибке, которое  ясно  и  понятно  указывают  на  проблему  с  введенными  данными  (например, "Пожалуйста, введите корректный email адрес",  "Пароль должен быть не менее 8 символов",  "Имя  может  содержать  только  буквы  и  цифры").

    * Форма должна  оставаться  в  том  же  состоянии,  что  и  до  отправки  (например,  не  перенаправляется  на  другую  страницу).

2.  Проверка работы формы при  ограниченном  подключении  к  Интернету:

* Описание: Проверить, как форма работает, когда интернет-соединение ограничено или отсутствует.

* Шаги:

    1.  Открыть форму регистрации.

    2.  Искусственно  ограничить  или  отключить  интернет-соединение.

    3.  Заполнить форму  валидными  данными.

    4.  Попытаться отправить форму.

    5.  Проверить, выводится ли сообщение об ошибке, связанное с отсутствием  интернет-соединения.

    6.  Восстановить  интернет-соединение.

    7.  Повторить  попытку  отправки  формы.

    8.  Проверить,  отправляются  ли  данные  на  сервер  после  восстановления  интернет-соединения.

* Ожидаемый результат:

    * При  отсутствии  интернет-соединения  форма  не  должна  быть  отправлена.

    * Должно быть выведено сообщение об ошибке,  связанное  с  отсутствием  интернет-соединения.

    * После  восстановления  интернет-соединения  форма  должна  быть  отправлена  на  сервер.

3.  Проверка  безопасности  форм  при  атаках  XSS:

* Описание:  Проверить,  что  форма  защищена  от  атак  XSS  (Cross-Site  Scripting),  которые  могут  быть  использованы  для  инъекции  вредоносного  кода  на  сайт.

* Шаги:

    1.  Изучить  документацию  по  безопасности  приложений,  чтобы  понять,  как  XSS  атаки  работают  и  как  защититься  от  них.

    2.  Использовать  инструменты  для  тестирования  на  уязвимости  XSS  (например,  Burp  Suite,  OWASP  Zap).

    3.  Попытаться  ввести  вредоносный  код  в  форму  регистрации  через  различные  поля.

    4.  Проверить,  как  форма  реагирует  на  ввод  вредоносного  кода  (например,  блокирует  его,  предотвращает  его  исполнение).

* Ожидаемый результат:  

    * Форма  должна  быть  защищена  от  атак  XSS.

    * Вредоносный  код  не  должен  быть  исполнен  и  не  должен  влиять  на  работу  сайта.

Важно: Для  тестирования  на  уязвимость  XSS  необходимо  иметь  достаточно  знаний  в  области  безопасности  приложений  и  использовать  специализированные  инструменты.

Хорошие ответы :)

А если еще усложнить задачу?

Запрос пользователя : 

Напиши 1 сложный тест-кейс для проверки формы регистрации

Ответ чата GPT:

Тест кейс: Проверка устойчивости формы регистрации к атаке SQL-инъекции

Описание: Проверить,  что  форма  регистрации  защищена  от  атак  SQL-инъекции,  которые  могут  быть  использованы  для  несанкционированного  доступа  к  базе  данных.

Шаги:

1. Изучение:  

    * Просмотреть  документацию  по  безопасности  приложений,  чтобы  понять,  как  атаки  SQL-инъекции  работают  и  как  защититься  от  них.

    * Изучить  основные  методы  предотвращения  SQL-инъекций,  такие  как  валидация  ввода,  использование  prepared  statements,  и  escape-символов.

2. Подготовка:

    * Выбрать  инструмент  для  тестирования  на  уязвимость  SQL-инъекции  (например,  Burp  Suite,  OWASP  Zap,  SQLMap).

    * Изучить  структуру  базы  данных  и  поля,  используемые  в  форме  регистрации.

3. Проведение теста:

    * Ввести  специальные  символы  и  SQL-команды  в  разные  поля  формы  регистрации  (например,  имя,  email,  пароль)  с  целью  изменить  запрос  к  базе  данных.

    * Использовать  инструменты  для  анализа  ответа  сервера  и  проверки  на  присутствие  в  нем  данных  из  базы  данных  (например,  имена  других  пользователей,  пароли,  конфиденциальная  информация).

    * Проверить  логи  сервера  на  присутствие  подозрительных  запросов  к  базе  данных. 

4. Анализ результатов:

    * Оценить  уязвимость  формы  регистрации  к  атаке  SQL-инъекции.

    * Определить  причины  уязвимости  (например,  отсутствие  валидации  ввода,  использование  неподготовленных  запросов).

    * Предложить  решения  для  устранения  уязвимости  (например,  внедрить  валидацию  ввода,  перейти  к  использованию  prepared  statements).

Ожидаемый результат:

* Форма  регистрации  должна  быть  защищена  от  атак  SQL-инъекции.

* Сервер  не  должен  отвечать  на  вредоносные  запросы  к  базе  данных.

* В  логи  сервера  не  должны  попадать  подозрительные  запросы  к  базе  данных.

Дополнительные заметки:

* Тестирование  на  уязвимость  SQL-инъекции  должно  проводиться  опытной  командой  разработчиков,  имеющей  знание  о  безопасности  приложений  и  баз  данных.

* Не  рекомендуется  проводить  такие  тесты  на  живом  сервере,  так  как  это  может  привести  к  непредвиденным  последствиям.

* Тестирование  на  уязвимость  SQL-инъекции  должно  быть  интегрировано  в  процесс  разработки  и  регулярно  проводиться  для  обеспечения  безопасности  приложения. 

Важно: Тестирование на  SQL-инъекцию  требует  значительных  знаний  в  области  безопасности  приложений  и  должно  проводиться  опытной  командой  разработчиков.

Предложения Chat GPT по тест-кейсам получились хорошие и адекватные. И в целом нейросети с данной задачей справляются неплохо, но следует отметить несколько моментов: 

  • Во всех примерах даны только негативные проверки, хотя в первую очередь должны проверяться позитивные сценарии. Для улучшения тестового покрытия в промте стоит указать создавать позитивные и негативные проверки.

  • Сгенерированные «сложные кейсы» не направлены на проверку редких кейсов и неочевидных логик, а просто требуют больших хардскилов для выполнения. Тут без специфики конкретного ТЗ не обойтись. Кейсы со сложной логикой придется делать самостоятельно.

  • Возможный разрыв между предложением нейросети и уровнем тестировщика. Проблема в следующем: если тестировщик сам не в состоянии накидать проверки, сможет ли он их провести?

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

Запрос пользователя:

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

Шаблон - {

  "id": 0,

  "username": "string",

  "firstName": "string",

  "lastName": "string",

  "email": "string",

  "phone": "string",

  "userStatus": 0

}

Ответ:

Вот пример реализации для создания пяти JSON-объектов пользователей, используя предоставленный вами шаблон:

[

  {

    "id": 1,

    "username": "JohnDoe",

    "firstName": "John",

    "lastName": "Doe",

    "email": "john.doe@example.com",

    "phone": "+1 425-678-9012",

    "userStatus": 1

  },

  {

    "id": 2,

    "username": "JaneSmith",

    "firstName": "Jane",

    "lastName": "Smith",

    "email": "jane.smith@example.org",

    "phone": "+1 206-789-1011",

    "userStatus": 1

  },

  {

    "id": 3,

    "username": "SamWashington",

    "firstName": "Sam",

    "lastName": "Washington",

    "email": "sam.washington@example.net",

    "phone": "+1 987-654-3210",

    "userStatus": 1

  },

  {

    "id": 4,

    "username": "AliceGreen",

    "firstName": "Alice",

    "lastName": "Green",

    "email": "alice.green@example.com",

    "phone": "+1 123-456-7890",

    "userStatus": 1

  },

  {

    "id": 5,

    "username": "BobWhite",

    "firstName": "Bob",

    "lastName": "White",

    "email": "bob.white@example.org",

    "phone": "+1 098-765-4321",

    "userStatus": 1

  }

]

Можно также попросить бота превратить все это в Insert-скрипт:

Запрос пользователя:

Теперь напиши INSERT SQL-скрипт, который вставит сгенерированные тобой объекты в таблицу с именем TABLE_1.

Ответ:

Для вставки сгенерированных JSON объектов в таблицу с именем TABLE_1 вам потребуется подготовить SQL скрипт. Предполагаем, что у вас есть столбцы, соответствующие каждому полю в JSON объекте. Ниже приведен пример SQL скрипта, который вставляет пять объектов в таблицу TABLE_1:

INSERT INTO TABLE_1(id, username, firstName, lastName, email, phone, userStatus) VALUES (1, 'JohnDoe', 'John', 'Doe', 'john.doe@example.com', '+1 425-678-9012', 1), (2, 'JaneSmith', 'Jane', 'Smith', 'jane.smith@example.org', '+1 206-789-1011', 1), (3, 'SamWashington', 'Sam', 'Washington', 'sam.washington@example.net', '+1 987-654-3210', 1), (4, 'AliceGreen', 'Alice', 'Green', 'alice.green@example.com', '+1 123-456-7890', 1), (5, 'BobWhite', 'Bob', 'White', 'bob.white@example.org', '+1 098-765-4321', 1);

Этот скрипт вставляет каждый объект в строку таблицы. Обратите внимание, что вам нужно будет адаптировать этот скрипт под вашу конкретную базу данных и структуру таблицы.

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

Анализ ошибок и локализация багов

С созданием ТД с помощью ИИ мы разобрались. Проведение тестирования мы пропустили по причинам, которые объяснялись в вводной части. Переходим к следующему этапу работы QA – локализации дефектов. Это нетривиальный процесс и часто не быстрый, а так хочется отправить в нейросеть “error message” и попросить найти причину. Для начала проверим, может ли ИИ локализовывать логически.

Для этого дадим одну из стандартных задач собеседований:

Запрос пользователя: 

В веб интерфейсе программы есть страница с формой создания пользователя и страница со списком пользователей. в форме создания пользователя есть три поля «Имя», «Фамилия», «Отчество». При создании мы ввели в каждое поле валидные данные и отправили форму. На странице со списком пользователей у созданного пользователя отчество отображается не целиком, а только первые 5 символов. Это баг – должно быть целое отчество.

Предложи варианты локализации этого бага учитывая клиент-серверную сущность приложения.

Ответ:

Баги, подобные этому, могут возникать как на стороне клиента (веб-интерфейс), так и на стороне сервера (логика приложения). Вот несколько возможных вариантов локализации проблемы:

Варианты локализации бага:

Вариант 1: Ограничение длины строки на стороне сервера

Ошибка может заключаться в том, что на стороне сервера ограничена длина строки для поля Отчество. Например, на сервере могут быть установлены ограничения на максимальную длину строк при записи данных в базу данных или при передаче данных между клиентом и сервером.

Вариант 2: Проблема с фронтендом

Возможно, проблема связана с тем, как фронтенд отображает данные. Если используется шаблонный язык типа React или Vue, то возможно, что в компоненте, отвечающем за вывод списка пользователей, имеется ошибка в шаблоне. Проверьте код, отвечающий за вывод списка пользователей, и убедитесь, что он корректно обрабатывает все возможные значения и правильно показывает их на экране.

Вариант 3: Ошибка на уровне базы данных

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

Вариант 4: Проблемы с передачей данных между клиентом и сервером

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

Пошаговый план действий:

Анализ формы:

Убедитесь, что форма создания пользователя правильно принимает и передает данные. Используйте инструменты разработчика браузера для проверки сетевого трафика и структуры HTTP-запросов.

Работа с базой данных:

Проверьте структуру таблицы в базе данных, где хранятся пользователи. Убедитесь, что столбец Отчество допускает достаточно большую длину строки.

Контроль серверной логики:

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

Тестирование фронтенда:

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

Обновление кода:

Обновите соответствующую часть кода фронтенда и серверной части, чтобы устранить проблему с отображением отчества.

Подведение итогов

Для полной локализации проблемы необходимо провести комплексный анализ всех компонентов системы – от фронтенда до бэкенда и базы данных. Проверьте каждый шаг процесса передачи и обработки данных, чтобы найти источник ошибки и исправить его.

Довольно неплохо — предложения хорошие. Здесь стоит отвлечься и сказать, что соискатели до уровня мидл- в среднем отвечают на этот вопрос хуже в половине случаев. Какой-то из пунктов могут пропустить либо из-за очевидности, либо потому что не знают. У нейросети есть важное преимущество — очевидное она не пропускает.

А как ИИ справляется с анализом error message, стек-трейсов и т.д.? Это может быть очень полезно, потому что часто стек-трейсы очень длинные, а корневая причина скрыта где-то внутри них. Вот пример анализа стек-трейса на 32 000 символов:

Хороший результат, однако данный пример довольно простой — указание ошибки уже в нем было. Кроме того, в диалоговое окно поместилось только 3200 знаков, при том что полный стек-трейс содержит 32 000. 

Продолжаем анализировать логи, после чего выявим несколько следствий:

  • Чем меньше в стек-трейсе явных указаний на ошибку, тем более общий неконкретный и бесполезный ответ даст нейросеть. 

  • Запоминание контекста диалога приводит к деградации ответов. Все знают, что ИИ помнит предыдущие сообщения в чате — это позволяет ему хранить контекст и улучшать ответы. Но он делает это всегда, даже когда не требуется. В результате, если в один и тот же диалог присылать все новые и новые логи с ошибками, то в какой-то момент бот начнет путаться в вопросах, своих ответах, сращивать их и выдавать все более невалидные ответы. Данный факт был проверен на нескольких чат-ботах, и рано или поздно деградация ответов случалась, причем это происходило неожиданно. Вот пример анализа одного и того же стек-трейса в «замусоренном» диалоге (1) и в «чистом» (2):

В первом ответе ошибка никак не связана с кэшем, в логе об этом вообще не было сказано, однако рассуждения о кэше и о запросах select были подтянуты из других, не относящихся к данной ошибке логов. 

Во втором ответе из «чистого» диалога нет конкретики, но в целом суть происходящего передана верно.

Совет: если анализируете много ошибок, почаще обновляйте диалог, особенно, если ошибки разнородные. 

Создание отчетности о тестировании

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

Для проверки возможности генерации отчета тестирования в «закромах» нашелся старый чек-лист о тестировании одного pet-проекта. В нем есть таблица с номерами, приоритетами, названиями и статусам прохождения проверок. Все это было превращено в CSV и отправлено в один из чат-ботов с запросом: 

Бот подумал несколько секунд и дал ответ:

Примечание: «пройдено с багом» — авторский статус, указанный в источнике. Чем он отличается от «провалено» — неизвестно.

Что ж, обзорный отчет составлен неплохо. Раздела «Дополнительные проверки» в оригинальном файле нет, но, возможно, нейросеть сама вывела его. В целом основные моменты подсвечены и сделан краткий вывод. Попробуем улучшить отчет и добавить в него диаграммы. В этом же треде (чате) пишем запрос: «сделай диаграмму по статусам проверок». Получаем следующий ответ:

Здесь есть явные проблемы. И дело не в том, что диаграмма не очень «красивая», а в том, что статусы подсчитаны неверно. В представленном файле в статусе «пройдено» — 20 кейсов, а не 24; в статусе «пройдено с багом» — 7 проверок, а не 9. Всего в файле 28 кейсов, а не 35. Интересно, что 35 — это общее количество строк в файле. 

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

ИИ в автоматизации тестирования (написании автотестов)

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

Если Chat GPT попросить написать автотест на Java для проверки отправки POST-запроса с сериализацией данных класса в тело запроса, то ответ будет примерно таким:

Код подробно задокументирован и выглядит неплохо. Стоит отметить, что использование Spring RestTemplate — довольно необычный ход. В тестах более распространен Rest Assured, но это не проблема. Однако такие примеры мне не нравятся, поскольку недостаточно показательны: они ничего конкретно не тестируют, а также не несут практической нагрузки. Подобный код-болванка легко находится с помощью поисковика, поэтому мы с вами разберем, как ИИ справляется с более прикладными задачами.

Представим, что нам нужно в коде получать значения переменных из файла .gitlab-ci.yml. Это очень удобно для тестов, так как с помощью такого приема вы сможете запускать тесты на разные стенды, выбирать обращения к эндпойнтам через различные варианты фасадов и прокси, а также многое другое.

Я сформулировал следующее задание и отправил его в один из чат-ботов:

Вопрос:

В файле .gitlab-ci.yml есть переменная PATH_TO_ENDPOINT, которая имеет value: "variant1". В коде программы есть класс Experiment.kt. В классе Experiment.kt есть переменная pathType значение, которой нужно взять из PATH_TO_ENDPOINT.

Напиши пример, как это сделать, используя язык программирования Kotlin.

Ответ:

 Для того чтобы использовать значение переменной PATH_TO_ENDPOINT в вашем коде на Kotlin, вам потребуется загрузить значения конфигурации из вашего файла .gitlab-ci.yml. Предположим, что этот файл находится в корне проекта. Вот пример кода, который может вам помочь:

```kotlin

// Импортируем необходимые библиотеки для работы с конфигурацией

import com.intellij.openapi.diagnostic.Logger

import org.jetbrains.kotlin.config.KotlinCompilerVersion

import java.io.File

import javax.script.ScriptEngineManager

class EndpointLoader(private val logger: Logger) {

    private val scriptEngine = ScriptEngineManager().getEngineByName("JavaScript")

    

    fun loadEndpoint(): String? {

        // Загружаем файл .gitlab-ci.yml

        val gitLabCiYmlPath = File("./${System.getProperty("user.dir")}/.gitlab-ci.yml").absolutePath

        try {

            val result = scriptEngine.eval("var jsonContent = JSON.parse(require('fs').readFileSync(${gitLabCiYmlPath}, 'utf8')); return jsonContent['PATH_TO_ENDPOINT'];") as String

            if (result == null || result.isEmpty()) {

                throw IllegalArgumentException("Invalid value for PATH_TO_ENDPOINT in ${gitLabCiYmlPath}")

            }

            return result

        } catch (e: Exception) {

            logger.error("Error loading PATH_TO_ENDPOINT from $gitLabCiYmlPath", e)

            return null

        }

    }

}

fun main() {

    val logger = Logger.getInstance(Experiment::class.java)

    val loader = EndpointLoader(logger)

    val endpointValue = loader.loadEndpoint() ?: "DefaultEndPoint"

    println("Loaded endpoint: $endpointValue")

    

    // Теперь вы можете использовать endpointValue в вашем классе Experiment.kt

    class Experiment {

        var pathType: String = endpointValue

        // Другие методы класса Experiment...

    }

}

```

Пояснение:

1. Используем ScriptEngineManager и JSON.parse для чтения содержимого файла ``.gitlab-ci.yml.

2. Получаем значение переменной PATH_TO_ENDPOINT и возвращаем его.

3. Обрабатываем возможные исключения при чтении файла.

4. Вызываем метод main(), который создает экземпляр EndpointLoader, загружает значение переменной PATH_TO_ENDPOINT и использует его в классе Experiment.

Таким образом, ваш код будет загружать значение переменной PATH_TO_ENDPOINT из файла .gitlab-ci.yml и использовать его в вашем коде на Kotlin.

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

При этом получил другой ответ:

Чтобы использовать переменную окружения из файла .gitlab-ci.yml в программе на Kotlin, вы можете воспользоваться стандартной библиотекой Kotlin для доступа к переменным окружения. Вот пример того, как это сделать.

1. Убедитесь, что переменная окружения PATH_TO_ENDPOINT правильно настроена в вашем .gitlab-ci.yml. Например:

yaml

variables:

  PATH_TO_ENDPOINT: "variant1"

2. В вашем классе Experiment.kt вы можете получить значение переменной PATH_TO_ENDPOINT, используя функцию System.getenv(). Вот пример, как это можно реализовать:

kotlin

class Experiment {

    val pathType: String? = System.getenv("PATH_TO_ENDPOINT")

    fun printPathType() {

        if (pathType != null) {

            println("The path type is: $pathType")

        } else {

            println("PATH_TO_ENDPOINT is not set.")

        }

    }

}

fun main() {

    val experiment = Experiment()

    experiment.printPathType()

}

### Объяснение кода:

- System.getenv("PATH_TO_ENDPOINT") — это функция, которая возвращает значение переменной окружения с именем PATH_TO_ENDPOINT. Если переменная не существует, она вернет null.

- В классе Experiment мы инициализируем переменную pathType значением переменной окружения.

- Метод printPathType выводит текущее значение pathType.

Совсем другое дело. Строка val pathType: String? = System.getenv("PATH_TO_ENDPOINT") – то, что нужно. К слову, ту же самую информацию можно отыскать через классический поисковик по первой же ссылке. И еще: перед публикацией данной статьи я решил перепроверить это задание в первом чат-боте, и на этот раз он уже выдал «нормальный» совет — использовать System.getenv("PATH_TO_ENDPOINT"). При этом сама версия модели данного чат-бота не менялась, формулировка вопроса — тоже. Но во второй раз ИИ дал адекватный совет, непонятно почему.

Из всего этого можем сделать сразу несколько выводов: 

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

  • Во-вторых, даже одна и та же нейросеть может давать разную «адекватность» советов в разное время. 

  • В-третьих, пользователь ИИ-бота должен уметь «на глаз» определять качество ответа, для этого ему необходимо должным образом разбираться в языке программирования.

Другой интересный пример. С помощью Awaitility (для асинхронного тестирования) и AssertJ (для выражения утверждений) была написана достаточно объемная тестовая функция, которая периодически делает запрос и проверяет ответ на наличие маркеров успеха или провала. Эта функция умеет выдавать Success или Exception в зависимости от проверки утверждений. Проблема в том, что для формирования отчетов использовался модуль Allure, который относит к failed-тестам только Assert Error, а любой Exception относит к broken-тестам, то есть, к кейсам, которые сломались и не дошли до конца. В данном случае требовалось завернуть тестовую функцию внутрь другой, которая будет сводить результат до Success или Assert Error. Для этого я написал такой промт:

   У меня есть написанный на Kotlin тестовый метод customMessage, который выглядит так:

    fun customMessage() { val integer = 1 assertThat(integer).isEqualTo(0) }

    Мне нужно внедрить assertThat(integer).isEqualTo(0) внутрь другой конструкции assert, которая будет проверять, выполнен внутренний assertion или нет.

Ответ:

И объяснение:

Компактная функция, но меня сразу смутил assertFailsWith<AssertionError>. Я вчитывался в объяснение и попытался понять, почему так, после чего поменял в исходном промте assertThat(integer).isEqualTo(0) на assertThat(integer).isEqualTo(1). 

Ответ сразу изменился:

fun customMessage() {

        val integer = 1

        assertThatCode { assertThat(integer).isEqualTo(1) }

            .doesNotThrowAnyException()

    }

В чем же дело? В блоке, кода я объявил integer = 1, но ожидал isEqualTo(0). Я сделал это специально, поскольку экспериментировал над трансформацией ошибок, а также с их текстами. Поэтому нужен был тест, который бы проваливался постоянно. Но я не учел (и не предполагал), что нейросеть посчитает такое поведение обязательным и подстроит под него весь дальнейший код. 

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

  • Указывайте в промте только необходимый объем информации. Старайтесь не предоставлять лишнего.

  • Если ответ нейросети кажется странным, внимательно посмотрите на промт — сделайте его более структурированным или поменяйте формулировку.

Однако есть и положительные примеры кода от нейросетей. Например, однажды у меня была задача парсить SQL-скрипты и извлекать из них имена таблиц. Делать это нужно было с помощью строковых функций PostgreSQL. Я мало работал со строковыми функциями, поэтому пошел читать документацию к PostgreSql. Прочитанное мне не очень понравилось, стиль изложения мне не подошел и я обратился к нейросети. 

Запрос был таким:

Есть база данных на движке PostgreSQL. В Таблице Table_1 есть ячейка query_text, в которой содержится строка: “Равным образом дальнейшее развитие различных форм деятельности играет важную schema1_Customers  роль в формировании системы schema1_Employees обучения кадров, соответствует насущным потребностям schema1_Categories.”

    Напиши скрипт, который извлечет все подстроки schema1_

Содержание ячейки query_text я скомбинировал из текста-рыбы и случайных названий таблиц. Все это наиболее подходящим образом имитирует SQL-скрипты.

Нейросеть предоставила такой ответ: 

SELECT unnest(regexp_matches(query_text, 'schema1_\w+', 'g')) AS match

regexp_matches – функция PostgreSQL, которая находит все совпадения регулярного выражения в строке.

unnest – функция PostgreSQL, которая служит для преобразования массива значений в набор строк. Она позволяет развернуть элементы массива в отдельные строки результата.

'schema1_\w+' – регулярное выражение, которое ищет строку, начинающуюся с schema1_, за которым следует одна или несколько букв, цифр или символов подчеркивания (\w+).

'g' – флаг, означающий глобальный поиск, то есть будут найдены все вхождения подстрок, а не только первое.

Полученный результат мне полностью подошел. Но особенно порадовало понятное мне объяснение. Я попросил пояснить и дать примеры функции regexp_matches с шаблонами и флагами, на что получил наиболее понятный (для меня) ответ, чем в документации. 

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

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

Заключение

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

Что получается хорошо:

  • Генерация тестовых данных по шаблону. Отличная вещь! Самая правильная работа для нейросети – генерировать сущности, похожие на реальные.

  • Создание черновика для тестовой документации. Нейросеть не забывает банальные проверки и в целом базовый набор кейсов получается достойный.

  • Быть интерактивным учебником. ИИ обстоятельно и с примерами умеет объяснять код, функции ЯП. Чаще всего эти объяснения дельные и помогают решить проблему.

Что получается со средней эффективностью: 

  • Написание кода тестов. Почему я отнес этот пункт к средним успехам? Качество генерации напрямую зависит от того, как ставятся задачи нейросети. Код хорошо работает только для простых и шаблонных тестов. Я часто пользуюсь ИИ для «последнего шага» при написании кода. Но вместе с этим качество кода резко снижается, если нужно написать что то нетривиальное, либо, например, создать свой микрофреймворк. Также существует проблема, что на один и тот же вопрос ответы разных чат-ботов могут быть разными, более того, у одного и того же бота сегодня могут быть ответы одни, а через неделю уже другие. В половине случаев нужно использовать другую LLM для перепроверки.

Что получается скорее плохо: 

  • Локализация ошибок по стек-трейсам. Практически бесполезна. Работает хорошо, только если в стеке есть явное указание на ошибку. Локализация по описанию воспроизведения ошибки в действительности еще более бесполезна, потому что дольше придется описывать контекст, чем самостоятельно локализовывать. В целом, чем лучше знаешь систему, тем меньше пользы от ИИ в этом деле.

  • Создание отчетности о тестировании на основе входного файла. Все потому что LLM часто (почти в каждом случае) путает причину и следствие (особенно ИИ не любит названия тест-кейсов) и делает в отчете значимые ошибки в подсчетах и выводах. Вероятность этого получилось уменьшить путем подготовки входного файла, но время на такую подготовку затрачивается довольно много, а в итоге профит от использования LLM обнуляется.

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

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

Удачи на проектах! :)

Спасибо за внимание!

Больше авторских материалов для QA-специалистов от моих коллег читайте в соцсетях SimbirSoft – ВКонтакте и Telegram.

Теги:
Хабы:
+3
Комментарии0

Публикации

Информация

Сайт
www.simbirsoft.com
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия