Привет, друг! Если ты уже знаком с основами нагрузочного тестирования в k6 и хочешь вывести свои скрипты на новый уровень — читай дальше. Сегодня мы поговорим о том, как создавать читаемые, повторно используемые и масштабируемые тесты с использованием ES6-модулей в k6.
🧩 Зачем нам модули?
Представь, что ты пишешь тесты, которые:
- Легко поддерживаются: изменения в одном месте не ломают всё остальное.
- Повторно используются: один и тот же код можно использовать в разных тестах.
- Масштабируются: легко добавлять новые сценарии без переписывания старых.
Модули помогают достичь всего этого. В k6 поддерживаются ES6-модули, что позволяет организовывать код по принципу "одна ответственность — один файл".
🛠 Установка и настройка
Для начала убедимся, что у нас всё готово для работы с модулями.
- Создаём структуру проекта:my-k6-tests/
3. Настройка config.js:// config.js
export const baseUrl = 'https://example.com';
export const thresholds = {
http_req_duration: ['p(95)<500'],
};
📦 Пример 1: Модуль с функцией логина
Создадим модуль для логина.
// tests/login.js
import http from 'k6/http';
import { check } from 'k6';
import { baseUrl } from '../config.js';
export function login(username, password) {
const res = http.post(`${baseUrl}/login`, { username, password });
check(res, {
'login successful': (r) => r.status === 200,
});
return res.json('token');
}
🛒 Пример 2: Модуль для оформления заказа
Теперь модуль для оформления заказа.
// tests/checkout.js
import http from 'k6/http';
import { check } from 'k6';
import { baseUrl } from '../config.js';
export function checkout(token, cart) {
const res = http.post(
`${baseUrl}/checkout`,
JSON.stringify(cart),
{ headers: { Authorization: `Bearer ${token}` } }
);
check(res, {
'checkout successful': (r) => r.status === 200,
});
return res.json('orderId');
}
🧪 Пример 3: Основной тестовый сценарий
Теперь соберём всё вместе в основном тесте.
// tests/main.js
import { login } from './login.js';
import { checkout } from './checkout.js';
import { baseUrl, thresholds } from '../config.js';
export const options = {
thresholds: thresholds,
};
export default function () {
const token = login('user', 'password');
const cart = [{ productId: 1, quantity: 2 }];
checkout(token, cart);
}
🛠 Пример 4: Использование переменных окружения
Иногда полезно настраивать поведение тестов через переменные окружения.
// tests/main.js
import { login } from './login.js';
import { checkout } from './checkout.js';
import { baseUrl, thresholds } from '../config.js';
export const options = {
thresholds: thresholds,
};
export default function () {
const username = __ENV.USERNAME || 'user';
const password = __ENV.PASSWORD || 'password';
const token = login(username, password);
const cart = [{ productId: 1, quantity: 2 }];
checkout(token, cart);
}
Запуск:
k6 run -e USERNAME=admin -e PASSWORD=secret tests/main.js
📦 Пример 5: Использование внешних библиотек
k6 поддерживает использование внешних библиотек через CDN.
// tests/main.js
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
export default function () {
console.log(randomItem([1, 2, 3]));
}
🧪 Пример 6: Тестирование с использованием сценариев
Сценарии позволяют моделировать различные нагрузки.
// tests/main.js
import { login } from './login.js';
import { checkout } from './checkout.js';
import { baseUrl, thresholds } from '../config.js';
export const options = {
scenarios: {
checkout: {
executor: 'ramping-vus',
stages: [
{ duration: '1m', target: 10 },
{ duration: '1m', target: 20 },
{ duration: '1m', target: 30 },
],
},
},
thresholds: thresholds,
};
export default function () {
const token = login('user', 'password');
const cart = [{ productId: 1, quantity: 2 }];
checkout(token, cart);
}
🧪 Пример 7: Тестирование с использованием групп
Группы помогают структурировать тесты.
// tests/main.js
import { login } from './login.js';
import { checkout } from './checkout.js';
import { baseUrl, thresholds } from '../config.js';
export const options = {
thresholds: thresholds,
};
export default function () {
group('User Login', () => {
const token = login('user', 'password');
});
group('Checkout', () => {
const cart = [{ productId: 1, quantity: 2 }];
checkout(token, cart);
});
}
🧪 Пример 8: Тестирование с использованием чеков
Чеки позволяют проверять ответы.
// tests/main.js
import { login } from './login.js';
import { checkout } from './checkout.js';
import { baseUrl, thresholds } from '../config.js';
export const options = {
thresholds: thresholds,
};
export default function () {
const token = login('user', 'password');
const cart = [{ productId: 1, quantity: 2 }];
const orderId = checkout(token, cart);
check(orderId, {
'orderId is not null': (id) => id !== null,
});
}
🧪 Пример 9: Использование сессий и хранения состояния
Когда ты тестируешь сложный пользовательский путь, важно сохранять промежуточные состояния — например, токен авторизации или ID корзины.
Создадим модуль session.js:
// tests/session.js
let session = {};
export function set(key, value) {
session[key] = value;
}
export function get(key) {
return session[key];
}
Применим его в основном тесте:
// tests/main.js
import { login } from './login.js';
import { checkout } from './checkout.js';
import * as session from './session.js';
export default function () {
const token = login('user', 'password');
session.set('token', token);
const cart = [{ productId: 1, quantity: 2 }];
const orderId = checkout(session.get('token'), cart);
console.log(`Order placed with ID: ${orderId}`);
}
📎 Такой подход позволяет эмулировать хранение состояния пользователя, особенно полезно при многошаговых сценариях.
🧪 Пример 10: Модуль для генерации случайных данных (faker)
Нам нужен способ генерировать данные пользователей или заказов. Давай напишем простой faker-модуль:
// tests/utils/faker.js
export function getRandomUsername() {
const id = Math.floor(Math.random() * 10000);
return `user_${id}`;
}
export function getRandomCart() {
const quantity = Math.floor(Math.random() * 5) + 1;
return [{ productId: 1, quantity }];
}
Применим в main.js:
import { login } from './login.js';
import { checkout } from './checkout.js';
import * as faker from './utils/faker.js';
export default function () {
const username = faker.getRandomUsername();
const token = login(username, 'password');
const cart = faker.getRandomCart();
const orderId = checkout(token, cart);
}
📦 Организация большого проекта (советы и структура)
Вот как может выглядеть хорошо организованный проект:
💡 Лучшие практики:
- Разделяй по доменам (user, order, etc.)
- Используй utils/ для вспомогательных функций
- Храни config.js для глобальных переменных
- Не бойся использовать SharedArray для данных и __ENV для гибкости
📈 Бонус: логгирование и кастомная аналитика
Добавим простой логгер:
// utils/logger.js
export function log(title, value) {
console.log(`[${title}] ${JSON.stringify(value)}`);
}
И используем:
import * as logger from './utils/logger.js';
export default function () {
const token = login('user', 'password');
logger.log('Token', token);
const cart = [{ productId: 1, quantity: 2 }];
const orderId = checkout(token, cart);
logger.log('Order ID', orderId);
}
🧠 Заключение
Поздравляю, ты прошёл погружение в модули в k6, научился:
- Делить код на логические части
- Повторно использовать функциональность
- Организовывать тестовый проект по всем канонам разработки
Теперь твои тесты будут читабельные, поддерживаемые и масштабируемые. А твои коллеги скажут: «О, кто-то тут явно знает, что делает».