До вмісту
L-SYSTEM

Де SQL входить у цикл тестування

Прев’ю-юніт: цей юніт відкритий і без запису на курс. Решта — після запису.

Заняття — вашою мовою: його веде асистент. Матеріал: англійська · Іспит: англійська, без перекладу Як під’єднати асистента

Баг, який закрився сам

Консультант Aldervane списує вісім годин на аудиторський проєкт Nordvale. Екран табеля показує запис. Тижневе зведення показує вісім годин. Консультант задоволений, тестувальник позначає кейс як пройдений, а через три тижні менеджер проєкту повідомляє, що Nordvale недовиставили рахунок на вісім годин.

На екрані не було нічого хибного. Рядок у TimeEntries було записано з EngagementId, що вказував на закритий проєкт, а завдання виставлення рахунків пропускає закриті проєкти. Кожен шар над базою даних був узгоджений, і кожен шар над базою даних повідомляв те саме хибне.

A monitor shows a turquoise check mark labelled "What the UI shows"; a dashed line leads to an amber cube labelled "What was written"
ІлюстраціяA monitor shows a turquoise check mark labelled "What the UI shows"; a dashed line leads to an amber cube labelled "What was written"
Опис

An isometric scene on a dark navy background. On the left, a frosted-glass monitor displays a glowing turquoise square with a white check mark; its stand is labelled "What the UI shows". A thin dashed line runs from the screen to the right, to a grey pedestal carrying one amber cube, labelled "What was written". The point: the screen reports a success, while the row behind it is the suspect one — here, a time entry attached to a closed engagement. The dashed line is the only connection the tester has between the two, and the only way to follow it is a query.

Саме для цієї ситуації й існує курс. Інтерфейс може повідомити вам лише те, що думає інтерфейс. Коли потрібно знати, що система записала насправді, дивитися можна рівно в одне місце.

Чотири моменти

Упродовж циклу тестування запит — єдиний доступний доказ у чотирьох точках.

До тесту — підготовка стану. Вам потрібен проєкт у певному стані: затверджений, частково виставлений у рахунок, з однією заявкою на відшкодування витрат, яка все ще чекає на розгляд. Проклікування до цього стану через UI займає двадцять хвилин і не повторюване. Скрипт підготовки займає секунди й створює той самий стан під час кожного прогону.

Після дії — перевірка запису. Застосунок каже, що зберіг. Ви перевіряєте, що він зберіг: яку таблицю, які стовпці, які значення і — зазвичай найцікавіше — які стовпці він залишив зі значеннями за замовчуванням, коли не мав би.

Під час розслідування — пошук форми дефекту. У баг-репорті сказано: «іноді з'являються дубльовані рядки рахунку». Запит до InvoiceLines із групуванням за проєктом і описом рядка перетворює «іноді» на «на 14 проєктах, усі створені після березневого релізу, в усіх зміна ставки посеред періоду».

Під час звірки — доказ, що нічого не втрачено. Міграція переносить три роки записів часу в TimeEntries зі StagingTimeEntries. Ніхто не може перевірити 400 000 рядків вручну. Кількість рядків, сума годин і різниця множин — можуть.

arrange Arrange state act Act through the UI or API arrange->act verify Verify the write act->verify ui the interface reports what the interface believes act->ui investigate Investigate a defect verify->investigate reconcile Reconcile a bulk operation verify->reconcile many rows db1 setup script db1->arrange db2 one known row, known values db2->verify db3 find what the bad rows share db3->investigate db4 counts, totals, set difference db4->reconcile
ІлюстраціяThe test cycle with the four points where a database query supplies the evidence
Опис

Stages left to right: Arrange state, Act through the UI or API, Verify the write, Investigate a defect; a dashed branch from Verify, labelled "many rows", leads to Reconcile a bulk operation. The Act stage has a dotted note: the interface reports what the interface believes. Four database cylinders feed evidence into four stages, in the accent colour: a setup script into Arrange; one known row with known values into Verify; find what the bad rows share into Investigate; counts, totals and set difference into Reconcile. Act is the only stage with no database cylinder of its own.

Чотири моменти різняться тим, що вам уже відомо. Підготовка: ви знаєте мету й будуєте її. Перевірка: ви точно знаєте, який рядок і які значення очікувати. Розслідування: ви ще не знаєте, що спільного в поганих рядків. Звірка: ви взагалі не можете перевірити рядки окремо, тож натомість порівнюєте сукупності.

Спершу питання, потім запит

Найдорожча помилка в цій дисципліні — не синтаксична. Синтаксичні помилки заявляють про себе самі. Дорога помилка — це запит, який виконується без помилок, повертає правдоподібні рядки й відповідає на питання, якого ніхто не ставив.

Тестувальник пише:

SELECT * FROM TimeEntries WHERE EngagementId = 4821;

Рядки повертаються. Тестувальник робить висновок, що час списано. Але перевірне питання було не «чи є записи часу за цим проєктом», а «чи збережено щойно надісланий мною запис із тими годинами, датою та ставкою, які я надіслав, і чи прив'язаний він до відкритого проєкту». Це різні питання, і поставлено було лише одне з них.

Тому звичка — з першого юніта: сформулюйте перевірне питання одним реченням, словами, перш ніж писати будь-який SQL. Потім напишіть запит, що відповідає на це речення і ні на що більше. Коли запит повернувся і ви збираєтеся оголосити успіх, перечитайте своє речення й запитайте себе, чи справді результат його розв'язує.

Корисне речення має три частини — які рядки, які значення і що вважатиметься провалом. «Рівно один рядок у TimeEntries для співробітника 331 на 2026-03-14, з Hours = 8.0 і EngagementId, що вказує на проєкт, у якого Status — Open; нуль рядків, більше ніж один рядок або закритий проєкт — провал».

Це речення довше за запит, який із нього виходить. Це нормально, і в цьому весь сенс.

«Лише читання» — за замовчуванням

Ви працюєте в середовищі, яким користуються й інші люди. Колега посеред регресії на тій самій схемі. Завжди виходьте з того, що ваша сесія не одна.

Позиція за замовчуванням: читати. SELECT не може зіпсувати нікому другу половину дня.

Три ситуації виправдовують вихід із цього режиму, і кожна несе зобов'язання.

Підготовка стану, який не можна підготувати через UI. Зобов'язання: знати, як це відкотити, і відкотити.

Відтворення дефекту, якому потрібні дані в неможливому стані — рядок рахунку з NULL у ставці, табель, датований раніше за початок проєкту. Зобов'язання: те саме плюс записка тому, хто відповідає за середовище.

Прибирання після власного прогону тесту. Зобов'язання: зачіпати лише те, що створили ви, за ідентифікатором, який ви контролюєте.

Усе, що поза цими трьома, — робота когось іншого. Якщо виправлення потребує UPDATE на даних, схожих на продуктивні, це запит на зміну, а не крок тесту — і те, що у вас є право його виконати, не те саме, що повноваження на це.

Механіка безпечного виходу з режиму за замовчуванням — явні транзакції, виконання SELECT перед DELETE, що ROLLBACK відкочує і чого не відкочує — це юніт 3. Поки ви його не прочитали, залишайтеся на SELECT.

Перш ніж щось запускати: дані клієнта не залишають середовища

Кожен запит у цьому курсі написано до ENGAGE — вигаданої системи, що належить вигаданій фірмі. На реальному проєкті рядки, які ви вибираєте, конфіденційні для клієнта — гонорари, ставки співробітників, невиставлений час, іноді власні операційні дані клієнта, що надійшли в межах аудиторського мандата.

Ці рядки не потрапляють до ШІ-асистента, публічного форматувальника SQL, pastebin, знімка екрана в груповому чаті чи коментаря до тікета. Ні для того, щоб отримати допомогу із запитом. Ні тому, що інструмент обіцяє не навчатися на них.

Коли вам потрібна допомога із запитом, безпечно передаються дві речі: запит без результатів і задача, переказана на вигаданих значеннях. Обох майже завжди достатньо — складність майже ніколи не в даних. Юніт 22 розбирає складніші випадки: що вважається достатньо знеособленим, що додавати до дефект-репорту і де проходить межа з локально розміщеною моделлю.

Як виглядає ENGAGE

Як слід ви познайомитеся зі схемою в юніті 2. Поки що — її загальний вигляд:

Clients і Engagements нагорі — у клієнта багато проєктів, у проєкту є статус і діапазон дат. Staff — це люди; TimeEntries пов'язують співробітника з проєктом на дату, з годинами та ставкою. Approvals фіксують, хто що затвердив і коли. Invoices і InvoiceLines перетворюють затверджений час і ExpenseClaims на гроші. AuditLog фіксує зміни будь-чого з цього. StagingTimeEntries — куди приземляється міграція зі старої системи, перш ніж чомусь у ній почнуть довіряти, а ArchivedTimeEntries зберігає записи до 2024 року в тій самій формі, що й TimeEntries.

Одинадцять таблиць, одна фірма, і кожен дефект у цьому курсі живе десь усередині них.

Ціна

SQL дає тестувальникові прямий доказ — найсильніший з усіх. Ціна в тому, що прямий доказ не пробачає неточних питань. Перевірка через UI, що ставить не те питання, зазвичай виглядає на екрані дивно. Запит, що ставить не те питання, повертає охайний набір результатів і хибне відчуття, що щось перевірено.

Усе подальше так чи інакше — про цей розрив.

Завдання

Перевірка тут нічого не змінює: відповіді почнуть зараховуватися після запису на курс.

  1. Розподіліть кожну ситуацію за моментом циклу тестування, у якому запит до бази даних є доказом.

    1. Вам потрібен проєкт, який затверджено, але ще не виставлено в рахунок, а в UI немає способу привести його в цей стан
    2. У примітках до релізу сказано, що імпортовано 12 400 записів часу зі старої системи; вам потрібно знати, чи всі вони дійшли
    3. Користувачі повідомляють, що заявки на відшкодування витрат іноді втрачають посилання на чек; ви хочете знати, які це заявки і що в них спільного
    4. Ви надіслали табель через UI і хочете знати, що потрапило в таблицю
  2. Тестувальникові потрібно перевірити, що щойно надіслану заявку на відшкодування витрат збережено правильно для співробітника 512 за проєктом Nordvale. Він виконує: ```sql SELECT * FROM ExpenseClaims WHERE StaffId = 512; ``` Рядки повертаються, і тестувальник позначає кейс як пройдений. Що не так у тому, щоб вважати цей результат перевіркою?

  3. Списавши 8 годин для співробітника 331 на проєкт 4821, тестувальник виконує `SELECT * FROM TimeEntries WHERE EngagementId = 4821;`, бачить 312 рядків і позначає кейс як пройдений. У сценарії з початку цього юніта запис насправді було зроблено на закритий проєкт. Що показав би цей запит?

  4. Який із цих варіантів — повне перевірне питання, що називає, які рядки, які значення і що вважається провалом?

  5. Ви на спільному тестовому стенді, яким сьогодні по обіді користуються ще четверо тестувальників. Розподіліть кожну дію.

    1. SELECT останніх двадцяти рядків AuditLog, щоб побачити, що записав тест колеги
    2. UPDATE поля Status одного проєкту на 'Closed', щоб відтворити дефект недовиставлення рахунку
    3. DELETE трьох тестових записів часу, які ви вставили годину тому, впізнаваних за створеним вами ідентифікатором співробітника
    4. UPDATE усіх InvoiceLines з NULL у Rate на 0, бо NULL — явно проблема якості даних
  6. Що з цього НЕ належить до трьох ситуацій, які виправдовують вихід із режиму «лише читання» за замовчуванням?

  7. Ваш запит до даних проєкту реального клієнта повертає неочікувані суми, і ви хочете допомоги від ШІ-асистента. Чим безпечно поділитися?

  8. Подивіться на ілюстрацію ui-vs-row. Що позначає пунктирна лінія між монітором і бурштиновим кубом?

  9. Подивіться на схему sql-in-test-cycle. У якого етапу немає власного доказу з бази даних?

  10. Консультант подає заявку на відшкодування витрат на 145.00 EUR за вечерю з клієнтом за проєктом Nordvale (EngagementId 4821) з датою 2026-03-12. Сформулюйте перевірне питання одним реченням — не запит, — назвавши, які рядки, які значення і що вважається провалом.

    Це завдання судить рубрика автора — її розбирає асистент, а не сайт.