SQL для QA

Какие SQL-навыки реально нужны QA и почему даже базовые запросы резко усиливают расследование дефектов и проверку данных.

Обновлено:

Содержание

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. Скачайте оба файла, откройте терминал в их папке и сохраняйте одну сессию.

plain text
sqlite3 :memory:
-- В приглашении SQLite:
.read sql-for-qa-fixture.sql
SELECT COUNT(*) FROM qa_customers;
-- Ожидается: 4
SELECT COUNT(*) FROM qa_orders;
-- Ожидается: 5

Fixture создаёт временные таблицы текущей сессии. Новая :memory:-сессия пуста; повторный CREATE без сброса в той же сессии завершится ошибкой существующих таблиц. Для сброса закройте учебную сессию и создайте новую. Production-подключение и учётные данные не нужны.

Предскажите строки до чтения ответов

plain text
Задача практикума	Ожидаемый результат
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:

plain text
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 центов: проверка только итога пропустит ошибку.

Перенесите фильтр в условие соединения, чтобы сохранить клиентов без совпадения:

plain text
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 не доказывает правильность бизнес-результата.

Продолжить изучение

Расширить проверки базы данных

Описать расхождение данных в баг-репорте

Скачать общий SQL fixture

Скачать восемь задач SQL с ответами

SQLite documentation: SELECT, outer joins and filtering