Обычно SQL проверяют так:
SELECT * FROM orders WHERE status = 'paid';
И потом сравнивают: «вернулись нужные строки или нет».
Но в реальных системах чаще ломается не сам happy path, а скрытые свойства данных.
Например, для отчёта по заказам тест должен проверять не только конкретные строки, а правила:
-- сумма по пользователям должна совпадать с общей суммой
WITH by_user AS (
SELECT user_id, SUM(amount) AS total
FROM orders
WHERE status = 'paid'
GROUP BY user_id
),
overall AS (
SELECT SUM(amount) AS total
FROM orders
WHERE status = 'paid'
)
SELECT
(SELECT SUM(total) FROM by_user) = (SELECT total FROM overall) AS is_valid;
То есть вы тестируете не «мне вернулось 10 строк», а:
агрегаты не теряют деньги
join не размножает строки
фильтр не выкидывает валидные данные
NULL не ломает расчёты
сумма после группировки совпадает с суммой до группировки
каждый order попадает ровно в одну категорию
дедупликация не удаляет нужные записи
Особенно полезный приём - тест на размножение строк после JOIN:
WITH before_join AS (
SELECT COUNT(*) AS cnt
FROM orders
),
after_join AS (
SELECT COUNT(*) AS cnt
FROM orders o
JOIN users u ON u.id = o.user_id
)
SELECT
after_join.cnt <= before_join.cnt AS no_unexpected_multiplication
FROM before_join, after_join;
Если после JOIN строк стало больше без явной причины - у вас почти наверняка проблема с кардинальностью.
Хороший SQL-тест проверяет не только ответ, а свойства запроса, которые должны оставаться истинными при любых данных. Именно так ловятся баги, которые не видно на маленьком тестовом датасете.
https://www.youtube.com/shorts/Rj2HKshtWO8