Зачем ревьюить тестовый код?

Тестовый код — это продакшн-код. Он запускается в CI/CD-пайплайнах, влияет на решения о деплое и поддерживается годами. Тем не менее, многие команды относятся к нему как к второсортному. Результат: хрупкий, неподдерживаемый набор тестов, которому никто не доверяет.

Чек-лист ревью

1. Тест проверяет то, что заявляет?

// ПЛОХО — имя говорит "создание" но тест проверяет только навигацию
@Test
void testUserCreation() {
    loginPage.login("admin", "pass");
    createUserPage.fillForm("Alice", "alice@test.com");
    createUserPage.submit();
    // Нет проверки, что пользователь действительно создан!
}

// ХОРОШО — проверка соответствует имени
@Test
void testUserCreation() {
    loginPage.login("admin", "pass");
    createUserPage.fillForm("Alice", "alice@test.com");
    createUserPage.submit();
    assertTrue(userService.exists("alice@test.com"));
}

2. Именование тестов

// ПЛОХО
@Test void test1() { ... }

// ХОРОШО
@Test void should_showDashboard_when_loginWithValidCredentials() { ... }
@Test void should_showError_when_loginWithExpiredPassword() { ... }

3. Структура Arrange-Act-Assert

@Test
void should_applyDiscount_when_couponIsValid() {
    // Arrange
    Order order = OrderFactory.createWithTotal(100.00);
    Coupon coupon = CouponFactory.createValid("SAVE20", 20);
    // Act
    order.applyCoupon(coupon);
    // Assert
    assertEquals(80.00, order.getTotal(), 0.01);
}

4. Одна задача на тест

5. Без логики в тестах

// ПЛОХО — логика в тесте
@Test void testUserRoles() {
    for (String role : List.of("admin", "user")) {
        if (role.equals("admin")) assertTrue(user.canDelete());
    }
}

// ХОРОШО — отдельные тесты
@Test void admin_canDelete() { ... }
@Test void regularUser_cannotDelete() { ... }

Типичные анти-паттерны

Mystery Guest

Тест зависит от невидимого внешнего состояния.

Eager Test

Тест проверяет слишком много за раз.

Гигант

Метод на 100+ строк, невозможный для понимания с первого взгляда.

Чувствительное равенство

// ПЛОХО
assertEquals(expectedUser.toString(), actualUser.toString());
// ХОРОШО
assertEquals("Alice", actualUser.getName());

Захардкоженные ожидания

// ПЛОХО
await page.waitForTimeout(5000);
// ХОРОШО
await expect(page.locator('.result')).toBeVisible();

Правила ревью для команд

Что проверять ревьюерам

  1. Корректность проверок
  2. Изоляция теста
  3. Ясность именования
  4. Независимость данных
  5. Отсутствие рисков нестабильности
  6. Надлежащая очистка
  7. Читаемость

Что НЕ придирать

  • Мелкие предпочтения форматирования
  • Выбор библиотеки проверок
  • Значения тестовых данных, не влияющие на поведение

Упражнения

Упражнение 1: Обнаружение анти-паттернов

Ревьюируйте 5 примеров тестового кода, найдите все анти-паттерны, предложите исправления.

Упражнение 2: Рефакторинг именования

Переименуйте 10 плохо названных методов по конвенции should_outcome_when_condition.

Упражнение 3: Документ стандартов

Создайте документ стандартов ревью тестового кода с конвенциями, правилами, анти-паттернами и примерами.