Динамическая генерация тестовых сценариев

Основы динамического тестирования

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

Ключевые принципы динамического тестирования:

  • Параметризация тестов – возможность запускать один и тот же тест с разными входными данными.
  • Генерация сценариев на лету – формирование тестов в цикле на основе массива объектов или данных из внешних источников (JSON, CSV, базы данных).
  • Повторное использование шагов – создание универсальных функций, которые могут применяться в различных комбинациях.

Использование массивов данных для генерации тестов

В WebdriverIO поддерживается интеграция с тестовыми фреймворками, такими как Mocha или Jasmine, что позволяет использовать массивы данных для генерации тестов через циклы или методы forEach.

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

const testCases = [
    { username: 'user1', password: 'pass1', expected: true },
    { username: 'user2', password: 'wrong', expected: false },
    { username: 'admin', password: 'admin', expected: true },
];

describe('Авторизация пользователей', () => {
    testCases.forEach(({ username, password, expected }) => {
        it(`проверка логина для пользователя ${username}`, async () => {
            await browser.url('/login');
            const usernameInput = await $('#username');
            const passwordInput = await $('#password');
            const loginButton = await $('#loginBtn');

            await usernameInput.setValue(username);
            await passwordInput.setValue(password);
            await loginButton.click();

            const loginSuccess = await $('#welcome').isDisplayed();
            expect(loginSuccess).toBe(expected);
        });
    });
});

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

Генерация тестов с использованием внешних источников

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

Пример загрузки данных из JSON:

const fs = require('fs');
const testData = JSON.parse(fs.readFileSync('./testData.json', 'utf-8'));

describe('Динамические тесты из JSON', () => {
    testData.forEach(({ input, expected }) => {
        it(`проверка ввода: ${input}`, async () => {
            await browser.url('/form');
            const inputField = await $('#inputField');
            const submitButton = await $('#submitBtn');

            await inputField.setValue(input);
            await submitButton.click();

            const result = await $('#result').getText();
            expect(result).toBe(expected);
        });
    });
});

Подход с JSON позволяет легко расширять тесты без изменения кода — достаточно добавить новые объекты с тестовыми данными.

Функции-хелперы и переиспользуемость шагов

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

Пример функции-хелпера:

async function login(username, password) {
    await browser.url('/login');
    await $('#username').setValue(username);
    await $('#password').setValue(password);
    await $('#loginBtn').click();
}

describe('Авторизация с помощью хелперов', () => {
    const users = [
        { username: 'user1', password: 'pass1' },
        { username: 'admin', password: 'admin' }
    ];

    users.forEach(({ username, password }) => {
        it(`логин для ${username}`, async () => {
            await login(username, password);
            const welcomeMessage = await $('#welcome').isDisplayed();
            expect(welcomeMessage).toBe(true);
        });
    });
});

Функции-хелперы позволяют легко комбинировать шаги, создавая новые сценарии без дублирования кода.

Использование it.each и параметризированных тестов

Для Mocha и Jasmine можно применять пакеты вроде mocha-each, которые упрощают синтаксис генерации тестов с множеством данных:

const forEach = require('mocha-each');

forEach([
    ['user1', 'pass1', true],
    ['user2', 'wrong', false],
]).it('проверка логина %s', async (username, password, expected) => {
    await browser.url('/login');
    await $('#username').setValue(username);
    await $('#password').setValue(password);
    await $('#loginBtn').click();

    const loginSuccess = await $('#welcome').isDisplayed();
    expect(loginSuccess).toBe(expected);
});

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

Асинхронная генерация тестов и внешние API

Иногда данные для тестов поступают из API или других асинхронных источников. WebdriverIO позволяет использовать async/await для загрузки данных перед генерацией тестов.

Пример:

let users;

before(async () => {
    const response = await fetch('https://api.example.com/users');
    users = await response.json();
});

describe('Тесты с данными из API', () => {
    users.forEach(({ username, password }) => {
        it(`логин для ${username}`, async () => {
            await browser.url('/login');
            await $('#username').setValue(username);
            await $('#password').setValue(password);
            await $('#loginBtn').click();

            const success = await $('#welcome').isDisplayed();
            expect(success).toBe(true);
        });
    });
});

Асинхронная генерация тестов позволяет тестировать реальные данные и интеграции, повышая надежность тестового покрытия.

Применение шаблонов и генераторов

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

Пример генератора тестов:

function generateLoginTests(users) {
    return users.map(({ username, password, expected }) => {
        return async function() {
            await browser.url('/login');
            await $('#username').setValue(username);
            await $('#password').setValue(password);
            await $('#loginBtn').click();

            const result = await $('#welcome').isDisplayed();
            expect(result).toBe(expected);
        };
    });
}

const testCases = generateLoginTests([
    { username: 'user1', password: 'pass1', expected: true },
    { username: 'user2', password: 'wrong', expected: false },
]);

describe('Динамически сгенерированные тесты', () => {
    testCases.forEach((testFunc, index) => {
        it(`тест ${index + 1}`, testFunc);
    });
});

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

Выводы по практике

Динамическая генерация тестов в WebdriverIO позволяет:

  • Создавать компактные и гибкие тестовые наборы.
  • Сокращать дублирование кода и упрощать поддержку тестов.
  • Легко интегрироваться с внешними источниками данных.
  • Комбинировать универсальные шаги в разнообразные сценарии.

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