White-box Testing (White-box Testing)
Тест знает о внутренней реализации системы: лезет напрямую в базу данных, вызывает приватные методы через рефлексию или проверяет SQL-запросы вместо поведения с точки зрения пользователя.
Симптомы
-
jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE ...")в тесте UI/API уровня -
ReflectionUtils.invokeMethod(privateMethod, service, args)для проверки приватной логики - Тест верифицирует структуру БД вместо пользовательского поведения
- Mock-объекты проверяют, что был вызван внутренний метод, а не что вернулся правильный результат
- Тест «ломается» при переименовании приватного метода или изменении схемы БД
Причины возникновения
- Желание убедиться, что данные «реально сохранились в БД», а не доверять UI
- Недоверие к тестируемой системе: «а вдруг UI врёт»
- Смешение уровней тестирования: в UI-тест вносится логика интеграционного теста
- Отсутствие разграничения ответственности между слоями тест-пирамиды
Почему это проблема
- Хрупкость к рефакторингу: изменили схему БД или переименовали метод — тест сломался, хотя поведение то же
- Нарушение уровней абстракции: UI-тест не должен знать о SQL и структуре таблиц
- Тест проверяет реализацию, а не контракт: потеряла смысл гарантия, что «система работает для пользователя»
- Сложная поддержка: нужно следить сразу за поведением и за реализацией
Решение
Проверять через тот же интерфейс, что использует пользователь:
// ❌ прямой SQL в UI-тесте
int count = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM users WHERE email = 'new@user.com'", Integer.class);
assertEquals(1, count);
// ✅ проверка через UI/API — тот же уровень абстракции
DashboardPage dashboard = loginPage.login("new@user.com", "Pass123!");
assertThat(dashboard.getGreeting()).isNotBlank();