← Назад к вопросам

Что такое паттерн given-when-then?

2.3 Middle🔥 121 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерн Given-When-Then

Given-When-Then — это популярный паттерн структурирования тестов (BDD — Behavior-Driven Development), который делает тесты более читаемыми и близкими к бизнес-требованиям. Этот паттерн помогает разработчикам и тестировщикам лучше понимать тестовый сценарий, описывая его на естественном языке.

Основные компоненты

Given (Дано)

Given определяет начальное состояние или предусловия перед выполнением теста. Это могут быть:

  • Инициализация объектов
  • Установка начальных значений
  • Подготовка тестовых данных
  • Конфигурация окружения

When (Когда)

When описывает действие или событие, которое должно произойти. Это:

  • Вызов метода
  • Выполнение операции
  • Запрос к API
  • Взаимодействие пользователя

Then (То)

Then проверяет результат выполнения действия. Это:

  • Утверждения (assertions)
  • Проверка вспомогательных эффектов
  • Верификация возвращаемых значений
  • Проверка состояния объектов

Пример без Given-When-Then

@Test
public void testCalculator() {
    Calculator calc = new Calculator();
    int result = calc.add(2, 3);
    assertEquals(5, result);
}

Этот тест непонятен — неясно, что мы проверяем и почему.

Пример с Given-When-Then

@Test
public void shouldReturnSumWhenAddingTwoPositiveNumbers() {
    // Given (Дано)
    Calculator calculator = new Calculator();
    int firstNumber = 2;
    int secondNumber = 3;
    
    // When (Когда)
    int result = calculator.add(firstNumber, secondNumber);
    
    // Then (То)
    assertEquals(5, result);
}

Теперь сразу понятна цель теста: "должен вернуть сумму при сложении двух положительных чисел".

Использование с фреймворком Mockito

@Test
public void shouldUpdateUserWhenValidDataProvided() {
    // Given
    User user = new User(1, "John", "john@example.com");
    UserRepository mockRepository = mock(UserRepository.class);
    UserService userService = new UserService(mockRepository);
    
    // When
    userService.updateUser(user);
    
    // Then
    verify(mockRepository, times(1)).save(user);
    verify(mockRepository, never()).delete(any());
}

Использование с фреймворком JUnit 5 и AssertJ

@Test
public void shouldReturnActiveUsersWhenFilteringByStatus() {
    // Given
    UserRepository repository = new InMemoryUserRepository();
    repository.save(new User("Alice", UserStatus.ACTIVE));
    repository.save(new User("Bob", UserStatus.INACTIVE));
    repository.save(new User("Charlie", UserStatus.ACTIVE));
    
    // When
    List<User> activeUsers = repository.findByStatus(UserStatus.ACTIVE);
    
    // Then
    assertThat(activeUsers)
        .hasSize(2)
        .extracting(User::getName)
        .containsExactlyInAnyOrder("Alice", "Charlie");
}

BDD с JBehave

Для полноценного BDD используется язык Gherkin (или похожие языки):

// Feature file (или прямо в коде)
public class UserAccountSteps {
    private User user;
    private UserService userService;
    private boolean result;
    
    @Given("пользователь с начальным балансом (\\d+) рублей")
    public void givenUserWithBalance(int balance) {
        user = new User();
        user.setBalance(balance);
    }
    
    @When("пользователь совершает платёж (\\d+) рублей")
    public void whenUserMakesPayment(int amount) {
        result = userService.processPayment(user, amount);
    }
    
    @Then("баланс должен быть равен (\\d+) рублей")
    public void thenBalanceShouldBe(int expectedBalance) {
        assertEquals(expectedBalance, user.getBalance());
    }
}

Сложный пример с исключениями

@Test
public void shouldThrowExceptionWhenDividingByZero() {
    // Given
    Calculator calculator = new Calculator();
    int dividend = 10;
    int divisor = 0;
    
    // When & Then
    assertThrows(ArithmeticException.class, () -> {
        calculator.divide(dividend, divisor);
    });
}

Преимущества Given-When-Then

  • Читаемость: Тест легко понять даже не-программистам
  • Структурированность: Ясное разделение подготовки, действия и проверки
  • Безопасность: Меньше ошибок благодаря чёткой структуре
  • Документация: Тесты служат живой документацией
  • Сотрудничество: Бизнес-аналитики и разработчики говорят на одном языке
  • Переиспользование: Легче переиспользовать код тестов

Best Practices

  • Название теста должно отражать Given-When-Then: shouldReturnErrorWhenAuthenticationFails
  • Не смешивай несколько When: Один тест = одно действие
  • Используй осмысленные имена переменных: вместо a, b используй user, product
  • Given должен быть простым: Сложная подготовка — признак проблем в дизайне
  • Then должен проверить всё важное: Не забывай проверять побочные эффекты

Паттерн Given-When-Then — это мощный инструмент для написания понятных, поддерживаемых и эффективных тестов, что является критически важным в профессиональной разработке.

Что такое паттерн given-when-then? | PrepBro