BDD: Behavior-Driven Development

BDD — методология разработки, расширяющая TDD: тесты описываются в терминах поведения системы на языке, понятном бизнесу и QA, с использованием структуры Given-When-Then.

Зачем нужно

BDD создаёт общий язык между разработчиками, тестировщиками и product owner. Тест «Когда пользователь добавляет товар в корзину, тогда счётчик увеличивается» читают все участники команды. Это снижает количество багов из-за недопонимания требований и делает тесты живой документацией.

Где используется

  • Описание поведения компонентов и сервисов через describe + it в Jest/Vitest
  • Gherkin-сценарии в Cucumber.js для E2E тестов
  • Acceptance testing совместно с PO и QA
  • Документирование API и бизнес-правил

Основной контент

Given-When-Then структура

Given  — начальное состояние (Arrange)
When   — действие пользователя или системы (Act)
Then   — ожидаемый результат (Assert)
And    — дополнительные условия к предыдущему шагу

BDD-стиль в Jest

// shoppingCart.test.js
describe('Корзина покупок', () => {
  describe('когда пользователь добавляет товар', () => {
    it('увеличивает количество товаров в корзине', () => {
      // Given
      const cart = new ShoppingCart();
      const product = { id: 1, name: 'Книга', price: 500 };

      // When
      cart.add(product);

      // Then
      expect(cart.count).toBe(1);
    });

    it('увеличивает количество при повторном добавлении', () => {
      const cart = new ShoppingCart();
      const product = { id: 1, name: 'Книга', price: 500 };

      cart.add(product);
      cart.add(product);

      expect(cart.count).toBe(1);
      expect(cart.getItem(1).quantity).toBe(2);
    });
  });

  describe('когда пользователь удаляет товар', () => {
    it('убирает товар из корзины', () => {
      const cart = new ShoppingCart();
      cart.add({ id: 1, name: 'Книга', price: 500 });

      cart.remove(1);

      expect(cart.count).toBe(0);
    });
  });
});

Cucumber.js + Gherkin

# features/cart.feature
Feature: Корзина покупок
  Как покупатель
  Я хочу управлять корзиной
  Чтобы покупать нужные товары

  Scenario: Добавление товара в корзину
    Given корзина пустая
    When я добавляю товар "Книга по тестированию" стоимостью 500 рублей
    Then в корзине 1 товар
    And общая сумма равна 500 рублей
// features/step_definitions/cart_steps.js
import { Given, When, Then } from '@cucumber/cucumber';
import { ShoppingCart } from '../../src/ShoppingCart';

let cart;

Given('корзина пустая', () => {
  cart = new ShoppingCart();
});

When('я добавляю товар {string} стоимостью {int} рублей', (name, price) => {
  cart.add({ name, price });
});

Then('в корзине {int} товар', (count) => {
  expect(cart.count).toBe(count);
});

BDD в Vitest

// Vitest поддерживает тот же синтаксис describe/it/expect
import { describe, it, expect } from 'vitest';

describe('AuthService', () => {
  describe('когда пользователь вводит неверный пароль', () => {
    it('выбрасывает ошибку AuthenticationError', async () => {
      const auth = new AuthService();
      await expect(auth.login('user', 'wrong')).rejects.toThrow('AuthenticationError');
    });
  });
});

Частые ошибки

  • BDD только как синтаксический сахар — описания типа describe('unit test 1') без смысла нарушают идею BDD; имена должны описывать поведение
  • Слишком детальные Gherkin-сценарии — шаги When я нажимаю кнопку с id="btn-submit" завязаны на реализацию; описывай намерение: When я отправляю форму
  • Gherkin без участия бизнеса — если сценарии пишет только разработчик, Gherkin становится лишним слоем без пользы

Связанные темы

Ресурсы