Тестування баз даних у 2026 році: що перевіряти, SQL-запити для тестувальника й інструменти
Користувач бачить інтерфейс, але все цінне живе в базі даних: замовлення, платежі, профілі, історія. Кнопка може показати «Збережено», а в таблицю потрапить неправильна сума, дубль чи «сирота» без батьківського запису. Міграція може пройти на тестовому сервері за секунду й заблокувати продакшн-таблицю на пів години. А запит, що летів на ста рядках, ляже на мільйоні.
Тестування баз даних перевіряє саме це: чи правильно дані записуються й зберігаються, чи цілі зв'язки між ними, чи безпечно змінюється схема, чи швидко працюють запити, і чи не витечуть персональні дані.
Короткий вибір
| Задача | Почати з | Альтернативи |
|---|---|---|
| Переглянути дані й виконати SQL | DBeaver | DataGrip, pgAdmin (PostgreSQL) |
| Модульні тести в самій БД | pgTAP (PostgreSQL) | tSQLt (SQL Server), utPLSQL (Oracle) |
| Інтеграційні тести зі справжньою БД | Testcontainers | DbUnit (Java), Neon (гілки бази) |
| Тестові дані | Faker.js | Mockaroo |
| Міграції схеми | Flyway | Liquibase, Atlas |
| Перевірка небезпечних змін і рев'ю SQL | Squawk (PostgreSQL) | Atlas, Bytebase, SQLFluff |
| Повільні запити | explain.dalibo.com | pgMustard, pgBadger |
| Навантаження на БД | HammerDB | sysbench, Apache JMeter, Grafana k6 |
| Маскування персональних даних | Greenmask | PostgreSQL Anonymizer |
| Якість даних у сховищах і ETL | dbt | Great Expectations, Soda, Datafold |
| SQL-ін'єкції | sqlmap | — |
| Поділитися прикладом у баг-репорті | DB Fiddle | — |
Що саме тестувати
| Напрям | Що перевіряємо | Приклад дефекту |
|---|---|---|
| Структура (схема) | Таблиці, стовпці, типи, довжини, значення за замовчуванням, індекси | Поле прізвища на 20 символів обрізає подвійні прізвища |
| Цілісність даних | Первинні й зовнішні ключі, UNIQUE, NOT NULL, CHECK | Видалили клієнта, а його замовлення лишилися «сиротами» |
| Коректність даних | Що дія в застосунку записала саме те, що мала | Знижка застосувалася двічі, сума в БД менша, ніж на екрані |
| Логіка в БД | Збережені процедури, функції, тригери, представлення | Тригер аудиту не спрацьовує при масовому оновленні |
| Транзакції й паралельність | Атомарність, ізоляція, блокування, взаємоблокування | Два одночасні замовлення продали останній товар двічі |
| Міграції | Застосування, відкат, час виконання, сумісність зі старим кодом | Міграція заблокувала таблицю замовлень на 20 хвилин |
| Продуктивність | Плани запитів, індекси, поведінка на великих обсягах | Сторінка звіту відкривається хвилину через відсутній індекс |
| Безпека | SQL-ін'єкції, права ролей, шифрування, маскування | Обліковий запис застосунку має права на DROP TABLE |
| Резервне копіювання | Що бекап створюється і з нього реально відновлюється база | Бекапи «були», але відновлення падає на половині |
| Якість даних | Повнота, унікальність, свіжість, узгодженість у сховищі даних | Звіт продажів за вчора порожній, бо ETL тихо впав |
SQL-перевірки, які варто знати напам'ять
Ці запити знаходять більшість проблем із даними. Назви таблиць умовні, синтаксис стандартний і працює в PostgreSQL та MySQL.
«Сироти»: дочірні записи без батьківського.
SELECT o.id, o.customer_id
FROM orders o
LEFT JOIN customers c ON c.id = o.customer_id
WHERE c.id IS NULL;
Дублікати там, де їх не має бути.
SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
Порожні значення в обов'язкових з точки зору бізнесу полях.
SELECT COUNT(*) AS total,
SUM(CASE WHEN phone IS NULL OR phone = '' THEN 1 ELSE 0 END) AS no_phone
FROM customers;
Узгодженість сум: заголовок замовлення проти рядків.
SELECT o.id, o.total, SUM(i.price * i.qty) AS items_total
FROM orders o
JOIN order_items i ON i.order_id = o.id
GROUP BY o.id, o.total
HAVING o.total <> SUM(i.price * i.qty);
Неможливі значення: від'ємні залишки, дати з майбутнього, статуси поза списком.
SELECT id, stock FROM products WHERE stock < 0;
SELECT id, created_at FROM orders WHERE created_at > CURRENT_TIMESTAMP;
SELECT DISTINCT status FROM orders;
Що змінила дія в застосунку. Перед тестом запам'ятайте MAX(id) або час, виконайте дію в інтерфейсі й подивіться нові та змінені рядки:
SELECT * FROM orders WHERE id > 15230 ORDER BY id;
SELECT * FROM audit_log WHERE created_at >= '2026-11-04 10:15:00' ORDER BY created_at;
Ці запити легко перетворити на автоматичні перевірки: тест падає, якщо запит повернув хоча б один рядок.
Ручне тестування бази даних
Для ручної роботи потрібен зручний клієнт. DBeaver Community безкоштовний і підключається практично до будь-якої СУБД, DataGrip від JetBrains безкоштовний для некомерційного використання й дуже добре розуміє SQL, а pgAdmin — офіційний інструмент для PostgreSQL. Важливо: на спільних середовищах підключайтеся користувачем лише з правами на читання, щоб випадково не змінити чужі дані.
Що варто перевіряти вручну:
- Дані після дій в інтерфейсі. Створили замовлення — подивіться, що з'явилося в усіх пов'язаних таблицях: замовлення, рядки, рух складу, платіж, журнал аудиту.
- Граничні значення. Максимальна довжина рядка, нуль і від'ємні числа, дуже великі суми, дати 29 лютого й 31 грудня, NULL проти порожнього рядка.
- Українські літери й емодзі. Ім'я «Ґалаґан-Їжакевич» має зберегтися й повернутися без «??». У MySQL для цього потрібне кодування
utf8mb4, а не стареutf8. Перевірте також сортування й пошук: у колаціях, нечутливих до діакритики, «ї» та «і» або «й» та «и» можуть вважатися однаковими, і унікальний індекс несподівано відхилить інше ім'я. - Часові пояси. Збережіть подію о 23:30 за Києвом і подивіться, якою датою вона потрапила в базу й у звіт. Окремо перевірте переходи на літній і зимовий час.
- Паралельні операції. Відкрийте дві сесії й одночасно змініть один запис, або в двох вкладках купіть останню одиницю товару. Саме тут ховаються помилки ізоляції транзакцій і блокувань.
- Видалення. Що стається з пов'язаними записами: каскадне видалення, заборона чи «м'яке» видалення з позначкою?
- Відновлення з бекапу. Хоча б раз на квартал разом з адміністраторами відновіть копію в окреме середовище й перевірте, що застосунок із нею працює.
Автоматичні тести
Модульні тести всередині БД
Якщо бізнес-логіка живе в збережених процедурах і тригерах, її варто тестувати там же.
- pgTAP для PostgreSQL перевіряє структуру схеми (чи є таблиця, стовпець, індекс, ключ) і результати функцій і запитів. Запуск через
pg_prove. - tSQLt для SQL Server: тести пишуться на T-SQL, кожен виконується в транзакції з відкатом, а
FakeTableізолює процедуру від реальних даних. - utPLSQL для Oracle: тести з анотаціями в пакетах PL/SQL і звіти покриття коду.
Інтеграційні тести зі справжньою базою
Тести застосунку на вбудованій «легкій» базі замість справжньої часто пропускають помилки: інші типи, інша поведінка NULL і сортування, відсутні функції. Краще тестувати на тій самій СУБД і версії, що й на проді.
- Testcontainers піднімає справжню базу в Docker-контейнері на час тестів і прибирає її після — для Java, .NET, Python, Go, Node.js та інших мов.
- DbUnit у Java-проєктах завантажує відомий набір даних перед тестом і порівнює таблиці після.
- Neon дозволяє за секунди створити гілку бази PostgreSQL з усіма даними — зручно для окремого середовища на кожен pull request.
Щоб тести не заважали один одному, використовуйте одну з трьох стратегій: транзакція з відкатом після кожного тесту, окрема чиста база на тестовий запуск або унікальні дані для кожного тесту.
Тестові дані
Для генерації правдоподібних даних підійдуть Faker.js (у коді, з підтримкою української локалі) і Mockaroo (у браузері, з експортом у SQL і CSV). Генеруйте не лише «гарні» дані, а й крайові: довгі рядки, апострофи в прізвищах (О'Коннор, Мар'яна), порожні необов'язкові поля, дуже старі й майбутні дати.
Міграції схеми: найризикованіше місце
Більшість аварій баз даних на проді пов'язані не з багами в запитах, а зі змінами схеми. Тому міграції мають бути в Git, проходити рев'ю й тестуватися так само, як код.
- Flyway від Redgate застосовує версійовані SQL-скрипти по черзі. Безкоштовна версія Community покриває основне; з травня 2025 року версію Teams новим клієнтам не продають, і для комерційних функцій лишилася Enterprise.
- Liquibase описує зміни в changelog-файлах і вміє робити відкат. З версії 5.0 (вересень 2025) Liquibase Community поширюється за ліцензією FSL (через два роки код переходить під Apache 2.0), а комерційна версія називається Liquibase Secure.
- Atlas генерує міграції з бажаної схеми й перевіряє їх лінтером на небезпечні зміни.
- Squawk — лінтер міграцій PostgreSQL: попередить, що
CREATE INDEXбезCONCURRENTLYзаблокує запис у таблицю. - Bytebase організовує рев'ю й схвалення SQL-змін для команди, а SQLFluff перевіряє стиль і типові помилки в SQL-коді.
Чек-лист тестування міграції:
1. Застосуйте міграцію на копії бази з реалістичним обсягом даних (замаскованих), а не на порожній.
2. Заміряйте час виконання й перевірте, чи блокує вона таблиці. Те, що на тестовій базі займає секунду, на проді може тривати годину.
3. Перевірте, що старий код застосунку працює з новою схемою, а новий — зі старою. Під час розгортання обидві версії працюють одночасно. Безпечний шлях — «розширити, перенести, звузити»: спочатку додати новий стовпець, потім перенести дані й код, і лише окремим релізом видалити старий.
4. Перевірте відкат або план відновлення.
5. Після міграції проженіть SQL-перевірки цілісності з розділу вище й тести pgTAP на структуру.
Оновлення версії СУБД — теж міграція. Підтримка MySQL 8.0 завершилася 30 квітня 2026 року, і багато команд зараз переходять на MySQL 8.4 LTS. PostgreSQL 18 вийшов у вересні 2025 року, а підтримку PostgreSQL 13 припинено в листопаді 2025-го. Перед оновленням проженіть повний регрес на новій версії й порівняйте плани ключових запитів: оптимізатор нової версії може обрати інший план.
Продуктивність запитів
- План виконання.
EXPLAIN ANALYZE(у PostgreSQL бажано зBUFFERS) показує, як база насправді виконала запит: які індекси використала, скільки рядків прочитала, де витратила час. Сирий план складно читати, тому вставте його в explain.dalibo.com (безкоштовно) або pgMustard (з порадами). - Журнали повільних запитів. Увімкніть
slow_query_logу MySQL абоlog_min_duration_statementу PostgreSQL. pgBadger перетворює журнал PostgreSQL на звіт із найповільнішими й найчастішими запитами. Розширенняpg_stat_statementsзбирає статистику запитів прямо в базі. - Типові проблеми: відсутній індекс на стовпці з
WHEREчиJOIN; функція над індексованим стовпцем (WHERE LOWER(email) = ...), яка не дає використати індекс;SELECT *у великих таблицях; проблема N+1, коли ORM робить окремий запит для кожного рядка списку; пагінація через великийOFFSET. - Обсяг даних. Завжди тестуйте на реалістичному обсязі: запит, що працює на 100 рядках, може бути катастрофою на 10 мільйонах.
Для навантажувального тестування самої СУБД є HammerDB (стандартні навантаження TPROC-C і TPROC-H) і sysbench (швидкі OLTP-тести MySQL і PostgreSQL). Навантаження через застосунок дають Apache JMeter з JDBC-запитами й Grafana k6. Детальніше — у статті «Навантажувальне тестування».
Безпека бази даних
- SQL-ін'єкції. Перевірте всі поля вводу, параметри URL і API. Автоматизує пошук sqlmap — тільки на власних системах або з письмовим дозволом. Головний захист у коді — параметризовані запити.
- Принцип мінімальних прав. Обліковий запис застосунку не повинен мати прав на
DROP,ALTERчи доступ до чужих схем. Перевірте це запитом до системних таблиць прав. - Чутливі дані. Паролі зберігаються лише як хеші, номери карток — не зберігаються взагалі або токенізовані, бекапи зашифровані.
- Помилки. Текст помилки бази не повинен потрапляти користувачу: він розкриває структуру таблиць.
Більше про це — у статті «Тестування безпеки».
Тестові дані без персональних даних
Найпростіший спосіб отримати реалістичну тестову базу — скопіювати продакшн. І найнебезпечніший: тестові середовища захищені гірше, доступ до них мають підрядники, а дані звідти потрапляють у скриншоти, баг-репорти й чати. Обробка персональних даних регулюється Законом України «Про захист персональних даних», а для клієнтів з ЄС — GDPR.
Тому копію проду перед передачею в тестування маскують:
- Greenmask робить дамп PostgreSQL і під час нього замінює імена, email, телефони й адреси на вигадані, зберігаючи зв'язки між таблицями.
- PostgreSQL Anonymizer дозволяє описати правила маскування прямо в схемі й робити статичне чи динамічне маскування.
Після маскування перевірте результат: пошукайте в тестовій базі кілька відомих реальних email чи телефонів — їх там не має бути.
Якість даних у сховищах і ETL
Якщо ви тестуєте аналітику, сховище даних чи конвеєри ETL, фокус зміщується з окремих транзакцій на великі набори: чи всі дані доїхали, чи немає дублікатів, чи свіжі вони, чи правильно пораховані агрегати.
- dbt має вбудовані тести
unique,not_null,accepted_values,relationshipsі модульні тести моделей. У червні 2026 року dbt Labs завершила злиття з Fivetran; dbt Core лишається відкритим. - Great Expectations і Soda описують «очікування» до даних і запускають їх у конвеєрах.
- Datafold порівнює дані до й після зміни коду чи міграції між базами й показує різницю прямо в pull request.
Базовий набір перевірок для будь-якого завантаження: кількість рядків у джерелі й цілі збігається, ключі унікальні, обов'язкові поля заповнені, контрольні суми (наприклад, сума продажів за день) збігаються з джерелом, дані не старші за очікуваний час.
Якщо ви тестуєте саму СУБД
Для команд, що розробляють бази даних чи їхні форки, є спеціалізовані підходи. SQLancer автоматично генерує бази й запити та шукає логічні помилки, коли СУБД повертає неправильний результат; так знайдено сотні дефектів у SQLite, MySQL, PostgreSQL та інших. Для розподілених баз відомий підхід Jepsen: перевірка гарантій узгодженості під мережевими збоями й падіннями вузлів.
Як звітувати про дефекти в даних
Хороший баг-репорт про базу даних містить:
- дію в застосунку, яка призвела до дефекту, і середовище;
- SQL-запит, що показує проблему, і його результат (без персональних даних);
- очікуваний результат: «сума в
orders.totalмає дорівнювати сумі рядків»; - ідентифікатори записів, щоб розробник знайшов їх у базі;
- версію СУБД і, якщо стосується, номер останньої застосованої міграції;
- для повільних запитів — план виконання й обсяг даних у таблицях.
Якщо проблему можна відтворити на маленькому прикладі, створіть його в DB Fiddle: схема, кілька рядків і запит, що повертає неправильний результат, доступні за одним посиланням.
План навчання на місяць
| Тиждень | Що робити |
|---|---|
| 1 | SQL-основи: SELECT, WHERE, JOIN, GROUP BY, HAVING. Інтерактивні уроки SQLBolt і вправи SQLZoo, детектив SQL Murder Mystery для закріплення. |
| 2 | Встановіть DBeaver і локальний PostgreSQL або MySQL. Створіть навчальну схему магазину, заповніть її даними з Mockaroo і напишіть усі SQL-перевірки з цієї статті. |
| 3 | Транзакції й рівні ізоляції: відтворіть у двох сесіях втрачене оновлення й взаємоблокування. Розберіться з EXPLAIN ANALYZE: додайте індекс і порівняйте плани в explain.dalibo.com. |
| 4 | Автоматизація: напишіть кілька тестів pgTAP або інтеграційний тест із Testcontainers, додайте міграції Flyway і перевірку Squawk у GitHub Actions. |
Більше тренажерів зібрано в підкатегорії Тренажери для тестувальників.
АІ в тестуванні баз даних
АІ-асистенти добре пишуть SQL за описом («знайди замовлення без оплати, створені понад добу тому»), пояснюють чужі запити й плани виконання, пропонують індекси й генерують тестові дані та крайові випадки. Багато клієнтів, зокрема платні редакції DBeaver і DataGrip, мають вбудованих АІ-помічників, які бачать структуру вашої бази.
Але є два правила. Перше: перевіряйте згенерований SQL перед виконанням, особливо UPDATE і DELETE — АІ легко пропустить умову WHERE чи переплутає стовпці. Друге: не вставляйте реальні персональні чи комерційні дані в публічні чат-боти; передавайте схему й замасковані приклади. АІ-інструменти для роботи з даними шукайте в підкатегорії Бази даних.
Про інші види тестування читайте в статтях «Тестування API», «Навантажувальне тестування», «Тестування безпеки» та «Інструменти для автоматизації тестування». Усі інструменти з цієї статті є в підкатегоріях Тестування і Бази даних.
Часті запитання
Чи потрібно тестувальнику знати SQL?
Так. Навіть мануальному тестувальнику SQL потрібен, щоб перевіряти дані після дій в інтерфейсі, готувати тестові дані й точно описувати дефекти. Рівня SELECT, JOIN, GROUP BY для старту достатньо.
Чим тестування БД відрізняється від тестування API?
Тестування API перевіряє, що повертає сервіс. Тестування БД — що насправді збереглося і чи цілі дані. API може відповісти «200 OK», а в базі опинитися неправильний запис.
Чи можна тестувати на копії продакшн-бази?
Лише після маскування персональних і чутливих даних. Реальні дані в тестовому середовищі — поширена причина витоків.
Як тестувати NoSQL-бази, наприклад MongoDB?
Принципи ті самі: коректність даних, валідація схеми документів, індекси й план запиту (explain()), продуктивність на реальному обсязі. Для інтеграційних тестів так само підходить Testcontainers.
Що робити, якщо логіка в збережених процедурах, а тестів немає?
Почніть з найкритичніших процедур (гроші, залишки, права) і напишіть для них модульні тести в tSQLt, pgTAP чи utPLSQL залежно від СУБД.
Не знаєте, з чого почати?
Запитайте Елю: вона підбере інструменти для тестування баз даних під ваш проєкт і рівень.
Дата перевірки фактів: 4 листопада 2026 року. Умови сервісів, ліцензії й терміни підтримки СУБД можуть змінюватися, тож перевіряйте їх на офіційних сайтах.
Виклик Асистента