Я — Solution Architect с 19 годами в IT, часто помогаю новичкам в тестировании. Джуны обычно жалуются на вагон теории, отсутствие практики и примеров, где основные алогритмы собраны вместе.
Я решил исправить эту проблему: взял OWASP Juice Shop — уязвимое веб-приложение, развернул его через Docker на http://135.181.239.135:4000 и протестировал с помощью ИИ.

В статье расскажу про:
ИИ для запуска тест-кейсов: автоматизация без глубоких знаний программирования.
Обучение ИИ-генерации тест-кейсов: как ИИ помогает придумывать сценарии.
Написание баг-репортов с ИИ: создание чётких и технически точных отчётов.
Эксплоративное тестирование с ИИ: поиск уязвимостей с подсказками ИИ.
ИИ как учитель: фидбэк и обучение тестированию.
Подводные камни ИИ для джунов: чего избегать, чтобы не плодить ошибки.
ИИ для запуска тест-кейсов
Притворюсь джуном-тестировщиком, который тестирует OWASP Juice Shop, развёрнутый в Docker. Задача — проверить форму логина, но навыков написания скриптов на Selenium или Playwright нет. Знаю, как проверять UI, кликать кнопки и заполнять формы, но кодировать это — проблема.
Для решения использую ИИ-инструмент Workik, который генерирует тесты на Cypress по текстовому описанию функциональности. Это упрощает автоматизацию: не нужно искать CSS-селекторы или разбираться с DOM вручную.
Шаг 1: Описываем задачу в Workik
Открываю https://workik.com/cypress-test-case-generator и в поле ввода описываю задачу:
Тестирование формы логина в OWASP Juice Shop на http://135.181.239.135:4000/#/login.
Проверить:
Успешный вход с email test@test.com и паролем password123.
Ошибка при неверном пароле wrongpass.
Ошибка при пустом email.

Жму «Generate», и Workik выдаёт код на Cypress. Вот пример (с техническими деталями):
// cypress/integration/login.spec.js
describe('Тестирование формы логина в OWASP Juice Shop', () => {
const baseUrl = 'http://135.181.239.135:4000/#/login';
beforeEach(() => {
cy.visit(baseUrl);
cy.intercept('POST', '/rest/user/login').as('loginRequest');
});
it('Успешный вход с валидными данными', () => {
cy.get('input[type="email"]').type('test@test.com');
cy.get('input[type="password"]').type('password123');
cy.get('button[type="submit"]').click();
cy.wait('@loginRequest').its('response').should('have.property', 'statusCode', 200);
cy.url().should('eq', 'http://135.181.239.135:4000/#/');
cy.get('.welcome-message').should('have.text', 'Welcome back!');
});
it('Ошибка при неверном пароле', () => {
cy.get('input[type="email"]').type('test@test.com');
cy.get('input[type="password"]').type('wrongpass');
cy.get('button[type="submit"]').click();
cy.wait('@loginRequest').its('response').should('have.property', 'statusCode', 401);
cy.get('.error-message').should('have.text', 'Invalid email or password');
});
it('Ошибка при пустом email', () => {
cy.get('input[type="password"]').type('password123');
cy.get('button[type="submit"]').click();
cy.get('.error-message').should('have.text', 'Email is required');
cy.get('input[type="email"]').should('have.class', 'ng-invalid');
});
});
Технические детали:
Используется cy.intercept для перехвата POST-запроса на /rest/user/login, что позволяет проверять HTTP-ответы.
Для успешного входа ожидается статус 200 и редирект на главную страницу.
Для неверного пароля сервер возвращает 401 Unauthorized, а фронт отображает сообщение об ошибке.
При пустом email валидация формы на фронте добавляет класс ng-invalid к полю, а сервер не вызывается.
Шаг 2: Настраиваем окружение и запускаем тесты
Устанавливаю Cypress в проекте:
mkdir juice-shop-tests
cd juice-shop-tests
npm init -y
npm install cypress --save-dev
npx cypress open





Создаю новый файл конфигурации login.spec.cy.js, вставляю код от Workik и запускаю тесты. Cypress открывает браузер, выполняет действия и проверяет результаты. Если тест падает, в логах видно:
URL запроса (/rest/user/login).
HTTP-статус (например, 401 для неверного пароля).
Тело ответа (например, {"error": "Invalid email or password"}).
Пример ошибки: Тест на неверный пароль падает, если сервер возвращает не Invalid email or password, а Wrong credentials. Лог Cypress показывает:
GET /rest/user/login 401
Response: {"error": "Wrong credentials"}
Исправляю ожидание:
cy.get('.error-message').should('have.text', 'Wrong credentials');
Шаг 3: Учимся на результатах
Добавляю тест на SQL-инъекцию через Workik, указав: «Проверить SQL-инъекцию с email ' OR '1'='1 используя cypress. Получаю:
describe('SQL Injection Test on Login', () => {
it('should attempt SQL injection with email', () => {
// Переход к странице логина
cy.visit('http://135.181.239.135:4000/#/login');
// Ввод вредоносного email
cy.get('input[name="email"]').type("' OR '1'='1");
// Ввод случайного пароля
cy.get('input[name="password"]').type('any_password');
// Нажимаем на кнопку логина
cy.get('button').contains('Login').click();
// Ожидаем и проверяем наличие сообщения об успешном входе
cy.url().should('not.include', '/login'); // Проверка, что мы не на странице логина
// Проверка, что сообщение об успешном логине или изменение в интерфейсе происходит
cy.contains('Logged in').should('exist');
});
});
Технический анализ:
Сервер корректно экранирует ввод, возвращая 401 вместо 200, что исключает возможность обхода авторизации.
Отсутствие SQL-ошибок в ответе (SQL syntax error) подтверждает защиту от инъекций.
Лог Cypress показывает, что запрос ушёл с экранированным телом: email=%27%20OR%20%271%27%3D%271.
Шаг 4: Интеграция в CI/CD
Добавляю тесты в GitHub Actions для автоматического прогона:
name: Cypress Tests
on:
push:
branches:
- main # Укажите вашу основную ветку
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
# 1. Шаг: Проверка исходного кода
- name: Checkout code
uses: actions/checkout@v3
# 2. Шаг: Настройка Node.js
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
# 3. Шаг: Установка зависимостей
- name: Install dependencies
run: npm install
# 4. Шаг: Запуск тестов Cypress в headless-режиме
- name: Run Cypress tests
run: npx cypress run --browser chrome --headless
# Настройка сохранения артефактов
continue-on-error: true # Позволяет процессу завершаться, даже если тесты не проходят
# 5. Шаг: Сохранение артефактов (логи, скриншоты, видео)
- name: Upload Cypress artifacts
uses: actions/upload-artifact@v3
with:
name: cypress-artifacts
path: |
cypress/videos
cypress/screenshots
cypress/results
Технические детали:
Cypress запускается в headless-режиме с Chrome.
Логи и артефакты (скриншоты, видео) сохраняются в GitHub Actions для анализа.
Плюсы:
Workik генерирует код, совместимый с CI/CD.
Логи HTTP-запросов помогают дебагать серверные ошибки.
Подводные камни:
Селекторы (например, .error-message) могут ломаться при редизайне фронта.
Бесплатная версия Workik ограничивает количество генераций.
Учимся через ИИ-генерацию тест-кейсов
Форма логина кажется простой, но тестировщик должен проверять краевые случаи: пустые поля, SQL-инъекции, длинные строки. Workik помогает генерировать такие сценарии.
Шаг 1: Описываем задачу
В Workik пишу:

Workik выдаёт код:
describe('Login Form Tests', () => {
beforeEach(() => {
cy.visit('http://135.181.239.135:4000/#/login'); // Переход к странице логина
});
it('should successfully log in with valid credentials', () => {
cy.get('input[name="email"]').type('test@test.com'); // Ввод email
cy.get('input[name="password"]').type('password123'); // Ввод пароля
cy.get('button').contains('Login').click(); // Нажимаем вход
cy.url().should('not.include', '/login'); // Проверяем, что не на странице логина
cy.contains('Logged in').should('exist'); // Проверка на наличие сообщения о входе
});
it('should display error for incorrect password', () => {
cy.get('input[name="email"]').type('test@test.com'); // Ввод email
cy.get('input[name="password"]').type('wrongpass'); // Неверный пароль
cy.get('button').contains('Login').click(); // Нажимаем вход
cy.contains('Invalid email or password').should('exist'); // Проверка на наличие ошибки
});
it('should display error for empty email', () => {
cy.get('input[name="email"]').type(''); // Пустой email
cy.get('input[name="password"]').type('password123'); // Ввод пароля
cy.get('button').contains('Login').click(); // Нажимаем вход
cy.contains('Invalid email or password').should('exist'); // Проверка на наличие ошибки
});
it('should handle SQL injection attempt', () => {
cy.get('input[name="email"]').type("' OR '1'='1"); // SQL-инъекция
cy.get('input[name="password"]').type('any_password'); // Неверный пароль
cy.get('button').contains('Login').click(); // Нажимаем вход
cy.contains('Invalid email or password').should('exist'); // Проверка на наличие ошибки
});
it('should display error for long email', () => {
const longEmail = 'a'.repeat(101) + '@test.com'; // Длинный email (>100 символов)
cy.get('input[name="email"]').type(longEmail); // Ввод длинного email
cy.get('input[name="password"]').type('password123'); // Ввод пароля
cy.get('button').contains('Login').click(); // Нажимаем вход
cy.contains('Invalid email or password').should('exist'); // Проверка на наличие ошибки
});
});
Технический анализ:
Тест на длинный email падает: сервер возвращает 500 вместо ожидаемого 400 Bad Request.
Лог Cypress: POST /rest/user/login 500, тело ответа: {"error": "Uncaught exception in user validation"}.
Это указывает на отсутствие серверной валидации длины строки, что приводит к неперехваченному исключению.
Шаг 2: Запускаем и анализируем
Запускаю тесты (npx cypress open). Тест с длинным email падает. Лог:
POST /rest/user/login 500
Response: {"error": "Uncaught exception in user validation"}
Исправляю ожидание:
cy.get('#errorMessage').should('contain', 'Internal Server Error');
Технический вывод:
Сервер не валидирует длину email, что вызывает исключение в бэкенде (вероятно, в Node.js/Express).
Рекомендация: добавить валидацию на уровне middleware (например, express-validator).
Шаг 3: Учимся думать как тестировщик
Workik подсказывает неочевидные случаи, вроде SQL-инъекций. Анализ логов учит:
Проверять HTTP-статусы (200, 401, 500).
Искать несоответствия между фронтом и бэкендом.
Упрощаем баг-репорты с ИИ
Найти баг — полдела. Нужно описать его так, чтобы разработчики поняли проблему. Пример: тест на длинный email выявил ошибку 500.
Шаг 1: Ловим баг
Тест:
it('Длинный email', () => {
const longEmail = 'a'.repeat(100) + '@test.com';
cy.get('#email').type(longEmail);
cy.get('#password').type('password123');
cy.get('#loginButton').click();
cy.wait('@loginRequest').its('response.statusCode').should('eq', 500);
});
Лог:
POST /rest/user/login 500
Тело ответа: {"error": "Uncaught exception in user validation"}
Скриншот: сообщение «Internal Server Error».
Шаг 2: Собираем баг-репорт
Баг-репорт:
Название: Ошибка 500 при отправке длинного email в форме логина
Шаги воспроизведения:
Открыть http://135.181.239.135:4000/#/login.
В поле email ввести строку длиной >100 символов (например, a...a@test.com).
В поле пароля ввести password123.
Нажать «Log in».
Ожидаемое поведение:
Сервер возвращает 400 Bad Request с сообщением Email too long.
Фронт отображает ошибку валидации.
Фактическое поведение:
Сервер возвращает 500 Internal Server Error.
Тело ответа: {"error": "Uncaught exception in user validation"}.
Фронт показывает «Internal Server Error».
Логи:
POST /rest/user/login 500
Запрос: {"email": "a...a@test.com", "password": "password123"}
Ответ: {"error": "Uncaught exception in user validation"}
Скриншоты: [Скриншот из cypress/screenshots]
Окружение:
Браузер: Chrome 126
Cypress: v10.3.0
Juice Shop: Docker, версия 14.0.0
Технический анализ:
Ошибка указывает на отсутствие валидации длины email в бэкенде.
Возможная причина: необработанное исключение в функции валидации (например, TypeError при работе со строкой).
Рекомендация: добавить проверку длины email в middleware или модели пользователя.
Шаг 3: Упрощаем с ИИ
Инструменты вроде BugBug анализируют логи и предлагают текст репорта. Пример:
Test failed: Expected 400, got 500
Suggested report:
- Steps: Send POST /rest/user/login with email >100 chars
- Expected: 400 Bad Request
- Actual: 500 Internal Server Error
- Logs: {"error": "Uncaught exception"}
Эксплоративное тестирование с ИИ
Эксплоративное тестирование — это исследование приложения без строгих тест-кейсов. В Juice Shop полно уязвимостей (XSS, SQL-инъекции), и ИИ помогает их найти.
Шаг 1: Получаем подсказки
В Workik пишу:
Исследовать OWASP Juice Shop на http://135.181.239.135:4000. Найти уязвимости в форме логина, корзине, поиске. Подсказать сценарии.
Workik предлагает:
Форма логина:
SQL-инъекция: Ввести ' OR '1'='1.
XSS: Ввести <script>alert('hack')</script>.
Переполнение буфера: Длинный email (>1000 символов).
Корзина:
Манипуляция количеством: Изменить поле quantity через DevTools.
CSRF: Проверить отсутствие токена в запросах.
Поиск:
XSS: Ввести <script>alert('boom')</script>.
SQL-инъекция: Ввести %' OR '1'='1.
Шаг 2: Исследуем
Проверяю XSS в форме логина:
Шаги:
В поле email ввожу <script>alert('hack')</script>.
Жму «Log in».
Результат:
Появляется alert с текстом hack.
Лог: скрипт выполняется без экранирования.
Баг-репорт:
Название: XSS-уязвимость в форме логина
Шаги:
Открыть http://135.181.239.135:4000/#/login.
В поле email ввести <script>alert('hack')</script>.
Нажать «Log in».
Ожидаемое поведение:
Ввод экранируется, alert не выполняется.
Сервер возвращает 400 или 401.
Фактическое поведение:
Выполняется JavaScript (alert).
Ответ сервера: 200 OK (ввод не валидируется).
Логи:
POST /rest/user/login 200
Тело запроса: {"email": "<script>alert('hack')</script>", "password": "password123"}
Технический анализ:
Отсутствует экранирование ввода на сервере (например, нет sanitize-html).
Рекомендация: добавить Content Security Policy (CSP) и экранирование.
ИИ как учитель
ИИ учит через фидбэк. Например, тест на длинный email падает. Лог:
POST /rest/user/login 500
{"error": "Uncaught exception"}
Workik подсказывает: «Проверь серверные логи». Я нахожу в логах Juice Shop:
TypeError: Cannot read property 'length' of undefined
at validateEmail (/app/server.js:123)
Урок:
Проблема в функции validateEmail, которая не проверяет тип входных данных.
Учусь анализировать стек вызовов.
Подводные камни
Слепая вера: Workik может упустить XSS в поиске, если не указать конкретно.
Ограничения бесплатной версии: Нет анализа серверных логов.
Контекст: ИИ не знает о скрытых API-уязвимостях Juice Shop.
А если вам нужен ИИ-помощник для сотрудника — познакомьтесь ближе с продуктами Minervasoft. Ассистент с генеративным ИИ Minerva Copilot встраивается в любую систему компании и подсказывает ответы из корпоративной базы знаний в зависимости от контекста. Быстро, качественно и со ссылками на статьи.
Кроме того, благодаря технологии DataHub система управления знаниями Minerva Knowledge становится корпоративным «мозгом» для GenAI. Платформа объединяет любые источники информации в компании, в том числе внутренние системы, базы знаний и другие хранилища данных.