SQL для QA - это не про глубокую оптимизацию запросов и не про работу DBA. Его главная ценность в другом: SQL помогает быстро увидеть правду о данных. Пока UI показывает одну картину, а API другую, база часто даёт самый прямой ответ на вопрос "что реально произошло".
Именно поэтому даже базовый SQL резко усиливает тестирование. Он помогает не гадать, а проверять: создалась ли запись, сохранился ли статус, нет ли дублей, правильные ли связи между сущностями, почему отчёт не сходится, куда пропали данные после действия пользователя.
Зачем QA нужен SQL
В реальной работе SQL чаще всего нужен для трёх задач:
- →проверить фактическое состояние данных после сценария
- →быстрее расследовать дефект
- →понять, проблема в UI, API, логике или самих данных
Очень много багов на самом деле оказываются не "проблемой кнопки", а проблемой состояния данных.
- →запись есть в UI, но в базе не хватает связанных строк
- →API вернул успех, но обновление не сохранилось
- →отчёт считает не те данные
- →после retry появились дубли
- →фильтр "не работает", потому что в базе данные уже не такие, как ожидает продукт
Без SQL такие вещи часто расследуются медленно и вслепую.
Что нужно знать в первую очередь
QA не нужен весь SQL как язык целиком. На старте достаточно уверенно владеть несколькими вещами.
- →SELECT - получить данные
- →WHERE - отфильтровать нужные строки
- →ORDER BY - посмотреть порядок
- →LIMIT - не тянуть лишнее
- →COUNT - быстро понять объём
- →JOIN - связать данные из нескольких таблиц
- →GROUP BY - увидеть агрегаты и дубли
- →IS NULL и IS NOT NULL - проверить пустые значения
Этого уже хватает для большой части ежедневных задач тестировщика.
Важно не просто знать синтаксис, а понимать, зачем он нужен. Если у тебя есть таблица заказов, таблица пользователей и таблица платежей, то SQL помогает не только "посмотреть строки", а проверить целостную картину сценария.
Что SQL особенно хорошо даёт QA
Самая сильная сторона SQL - точность.
Через UI ты видишь только то, что решили показать. Через API ты видишь только конкретный ответ конкретного вызова. Через SQL можно посмотреть на данные напрямую и ответить на практические вопросы:
- →запись вообще создалась?
- →сколько таких записей на самом деле?
- →есть ли дубликаты?
- →к какому пользователю привязана сущность?
- →сохранился ли правильный статус?
- →есть ли осиротевшие данные?
- →совпадает ли сумма с тем, что показано в интерфейсе?
- →изменилась ли запись после операции или только кажется, что изменилась?
Для QA это особенно важно в сценариях с интеграциями, очередями, ретраями, фоновыми задачами, массовыми обновлениями и сложными связями между сущностями.
JOIN для QA
Одна из самых полезных вещей для тестировщика - это JOIN. Именно он позволяет перестать смотреть на таблицы по отдельности и увидеть, как сущности реально связаны друг с другом.
- →у каждого заказа есть владелец
- →у заказа есть нужные order items
- →платёж привязан к правильному заказу
- →пользователь связан с правильной ролью
- →не осталось ли записей, которые ссылаются на несуществующий объект
Очень часто дефект не в том, что "записи нет", а в том, что она связана не с тем объектом или часть цепочки сломана. И без JOIN это трудно заметить.
Где QA чаще всего ошибается в SQL
- →путать NULL и пустое значение
- →забывать про дубли при JOIN
- →смотреть только на первую попавшуюся строку
- →выполнять write-запросы без нужды
Для QA safest path обычно такой: сначала читать, потом уже очень осознанно что-то менять и только в подходящей среде. В большинстве расследований достаточно SELECT.
Практический пример
Представь баг: пользователь говорит, что у него два одинаковых заказа.
Через UI это видно частично. Через API можно увидеть один endpoint. Через SQL можно проверить намного больше:
- →действительно ли в таблице заказов две записи
- →одинаковые ли у них бизнес-ключи
- →созданы ли они в один момент
- →есть ли у обеих одинаковые order items
- →связан ли дубль с повторным retry
- →есть ли два платежа или только один
- →это настоящий дубль или просто UI показывает одну запись дважды
Вот здесь SQL перестаёт быть "техническим бонусом" и становится реальным инструментом QA.
Что важно QA на практике
- →начинай с простого SELECT
- →сначала проверь одну сущность, потом связи
- →всегда уточняй, по какому ключу ищешь данные
- →не делай вывод по одной строке, если нужен общий паттерн
- →осторожно относись к write-запросам
- →если есть сомнение, сверяй SQL с тем, что показывает API и UI
SQL особенно силён не сам по себе, а как мост между слоями системы.
Что должен вынести QA из этой темы
- →SQL нужен QA не для "программирования базы", а для проверки правды о данных.
- →Даже базовых SELECT, WHERE, JOIN, COUNT и GROUP BY уже хватает для сильного расследования дефектов.
- →Очень много продуктовых багов оказываются проблемами состояния данных.
- →Один из самых полезных навыков тестировщика - уметь связывать между собой UI, API и базу.
- →SQL делает диагностику точнее, быстрее и спокойнее.
Что ещё почитать
- →Внутри базы: Database testing
- →Внутри базы: JSON и XML
- →Внешний материал: PostgreSQL joins tutorial
Практика на одном наборе данных: восемь проверенных задач
Используйте связанный практикум QA Hub и sql-for-qa-fixture.sql вместо второго несовместимого набора. В нём четыре вымышленных клиента и пять заказов; суммы — целые центы. Этот запуск выполняется в SQLite 3. В ресурсе описан переносимый SQL, но инструкция не утверждает, что здесь выполнена проверка на PostgreSQL. Скачайте оба файла, откройте терминал в их папке и сохраняйте одну сессию.
sqlite3 :memory:
-- В приглашении SQLite:
.read sql-for-qa-fixture.sql
SELECT COUNT(*) FROM qa_customers;
-- Ожидается: 4
SELECT COUNT(*) FROM qa_orders;
-- Ожидается: 5Fixture создаёт временные таблицы текущей сессии. Новая :memory:-сессия пуста; повторный CREATE без сброса в той же сессии завершится ошибкой существующих таблиц. Для сброса закройте учебную сессию и создайте новую. Production-подключение и учётные данные не нужны.
Предскажите строки до чтения ответов
Задача практикума Ожидаемый результат
1 Оплаченные заказы (101, 1, 1200), (103, 2, 700), (105, 3, 0)
2 Число заказов, включая ноль (1, Ada, 2), (2, Boris, 2), (3, Chen, 1), (4, Dina, 0)
3 Оплаченная выручка по клиентам (1, 1200), (2, 700), (3, 0), (4, 0)
4 Клиенты без заказов (4, Dina)
5 Дубли непустого email (ada@example.invalid, 2)
6 Неверная оплаченная сумма по условию (105, 0)
7 Не меньше двух заказов (1, 2), (2, 2)
8 Отсутствующий email (4, Dina)Номера задач и ответы совпадают со скачиваемым практикумом. Дубли email и оплаченный заказ с нулевой суммой добавлены намеренно. В реальном продукте дефект определяется требованиями. Нельзя выводить обязательность уникальности, положительной суммы или нормализации только из запроса.
Ловушка LEFT JOIN: сумма верна, клиент пропал
После загрузки общего fixture сравните два запроса. По правилу отчёт показывает всех четырёх клиентов, включая клиентов без оплаченных заказов. Первый запрос ставит условие paid в WHERE:
SELECT c.customer_id, COALESCE(SUM(o.amount_cents), 0) AS paid_cents
FROM qa_customers c
LEFT JOIN qa_orders o ON o.customer_id = c.customer_id
WHERE o.status = 'paid'
GROUP BY c.customer_id ORDER BY c.customer_id;Он вернёт (1,1200), (2,700), (3,0): Dina исчезнет. У её несопоставленной строки поля заказа равны NULL, поэтому WHERE её не сохраняет. Общая сумма всё ещё 1900 центов: проверка только итога пропустит ошибку.
Перенесите фильтр в условие соединения, чтобы сохранить клиентов без совпадения:
SELECT c.customer_id, COALESCE(SUM(o.amount_cents), 0) AS paid_cents
FROM qa_customers c
LEFT JOIN qa_orders o
ON o.customer_id = c.customer_id AND o.status = 'paid'
GROUP BY c.customer_id ORDER BY c.customer_id;Ожидается (1,1200), (2,700), (3,0), (4,0). Проверяйте и точные ID клиентов, и суммы. Для количества заказов нужен COUNT(o.order_id): COUNT(*) считает и несопоставленную строку outer join. Проверяйте NULL через IS NULL, а не = NULL. В практикуме эти случаи сопровождаются запускаемыми запросами.
Превращаем расхождение в доказательство
Запишите версию данных/fixture, диалект SQL, запрос, правило продукта, ожидаемые и фактические строки. Для упорядоченного сравнения явно задайте сортировку. Без требования к порядку сравнивайте множества или мультимножества, учитывая значимость дублей. Успешное выполнение SQL не доказывает правильность бизнес-результата.
Продолжить изучение
Расширить проверки базы данных
Описать расхождение данных в баг-репорте