Как объяснить программисту, что баг — это не «оно не работает»?
Вы когда-нибудь получали задачу в стиле: «Сделай, чтобы кнопка работала правильно»? Или, что ещё хуже, писали код, тесты зелёные, а заказчик говорит: «Ну, это не то, что я просил». Знакомая боль? Добро пожаловать в мир, где BDD (Behaviour-Driven Development) на JavaScript становится спасательным кругом.
BDD — это не просто очередная модная аббревиатура. Это подход, который заставляет разработчиков, тестировщиков и бизнес-аналитиков говорить на одном языке. На русском, живом, без «методологий» и «архитектурных парадигм». Сегодня мы разберём, как внедрить BDD в JavaScript-проект, напишем реальные тесты и поймём, почему это делает код чище, а жизнь — проще.
Что такое BDD и чем он отличается от TDD?
Давайте сразу расставим точки над «ё». BDD (Behaviour-Driven Development) — это эволюция TDD (Test-Driven Development). Если TDD говорит: «Сначала напиши тест, потом код», то BDD добавляет: «Но тест должен быть понятен бабушке-инвестору».
Ключевая идея BDD: мы тестируем поведение системы, а не её внутреннее устройство. Мы не спрашиваем: «Возвращает ли функция true?». Мы спрашиваем: «Может ли пользователь добавить товар в корзину и увидеть сумму заказа?». Разница колоссальная.
Для BDD на JavaScript существует специальный язык — Gherkin. Это такой псевдо-английский (или псевдо-русский), который выглядит как инструкция к конструктору Lego:
Функционал: Корзина покупок
Как зарегистрированный пользователь
Я хочу добавлять товары в корзину
Чтобы видеть итоговую стоимость
Сценарий: Добавление одного товара
Допустим пользователь авторизован
Когда он добавляет товар "Ноутбук" в корзину
Тогда в корзине отображается 1 товар
И общая стоимость равна 99900 рублей
Согласитесь, это читается как бизнес-требование, а не как код. И это главная фишка BDD.
Инструменты для BDD на JavaScript
Чтобы заниматься behaviour-driven development на JavaScript, нужны правильные инструменты. Вот три кита, на которых всё держится:
- Cucumber.js — самый популярный фреймворк для BDD. Он парсит Gherkin-сценарии и связывает их с кодом.
- Jest + Jest-Cucumber — если вы уже используете Jest, это идеальный вариант. Никакой магии, только чистая интеграция.
- Mocha + Chai + Gherkin — для тех, кто любит собирать конструктор вручную. Гибко, но больше кода.
Мы будем использовать Cucumber.js, потому что это стандарт индустрии. Установка простая:
npm install @cucumber/cucumber --save-dev
После этого создаём папку features/ — там будут жить наши .feature файлы. А в папке step_definitions/ — код, который оживляет сценарии.
Пишем первый BDD-тест: авторизация пользователя
Давайте представим, что мы делаем интернет-магазин. Первое, что нужно протестировать — вход в систему. Создаём файл features/login.feature:
# language: ru
Функционал: Авторизация пользователя
Как посетитель сайта
Я хочу войти в личный кабинет
Чтобы управлять своими заказами
Сценарий: Успешный вход с правильными данными
Допустим я нахожусь на странице входа
Когда я ввожу email "user@example.com" и пароль "123456"
И нажимаю кнопку "Войти"
Тогда я вижу приветствие "Добро пожаловать, Иван!"
Теперь нужно написать шаги (steps) — код на JavaScript, который выполнит эти действия. Создаём step_definitions/login.steps.js:
const { Given, When, Then } = require('@cucumber/cucumber');
const { expect } = require('chai');
// Состояние приложения (имитация)
let currentPage = '';
let userEmail = '';
let userPassword = '';
let isLoggedIn = false;
let greetingMessage = '';
Given('я нахожусь на странице входа', function () {
currentPage = 'login';
isLoggedIn = false;
});
When('я ввожу email {string} и пароль {string}', function (email, password) {
userEmail = email;
userPassword = password;
// Тут мог бы быть вызов реального API
if (email === 'user@example.com' && password === '123456') {
isLoggedIn = true;
greetingMessage = 'Добро пожаловать, Иван!';
}
});
When('нажимаю кнопку "Войти"', function () {
// Действие уже выполнено в предыдущем шаге
});
Then('я вижу приветствие {string}', function (expectedMessage) {
expect(greetingMessage).to.equal(expectedMessage);
});
Запускаем тесты командой npx cucumber-js. Если всё зелёное — вы только что написали первый BDD-тест. Поздравляю!
Продвинутый сценарий: проверка негативных кейсов
BDD особенно силён в описании граничных случаев. Добавим ещё один сценарий в наш файл login.feature:
Сценарий: Ошибка при неверном пароле
Допустим я нахожусь на странице входа
Когда я ввожу email "user@example.com" и пароль "wrongpass"
И нажимаю кнопку "Войти"
Тогда я вижу сообщение об ошибке "Неверный email или пароль"
Дописываем шаги в login.steps.js:
let errorMessage = '';
When('я ввожу email {string} и пароль {string}', function (email, password) {
userEmail = email;
userPassword = password;
// Негативный сценарий
if (email === 'user@example.com' && password !== '123456') {
isLoggedIn = false;
errorMessage = 'Неверный email или пароль';
}
});
Then('я вижу сообщение об ошибке {string}', function (expectedError) {
expect(errorMessage).to.equal(expectedError);
});
Обратите внимание: мы не трогаем код приложения. Мы просто описываем поведение. Если тест падает — значит, либо логика в шагах неверна, либо сама бизнес-логика не соответствует ожиданиям.
BDD в реальном проекте: как не выстрелить себе в ногу
Теперь, когда вы знаете теорию, давайте поговорим о практике. Behaviour-driven development — это не панацея. Вот несколько граблей, на которые наступают новички:
- Не пишите сценарии на каждый чих. BDD для критически важного поведения, а не для проверки геттеров и сеттеров.
- Исп