Раздел 10 — Данные и журналы

Экран говорит «сохранено» — база и журнал показывают, что сохранилось на самом деле

Прогресс курса Раздел 10 из 12

Что вы освоите в этом разделе

6 академических часов: 2 теории, 4 практики. Нужен DB Browser for SQLite (Windows, Linux, macOS; бесплатно). В Linux можно обойтись консольной программой sqlite3 (sudo apt install sqlite3). Снимки — DB Browser 3.13.1 в Windows 11.
01

Зачем смотреть в базу

Интерфейс и API показывают то, что программа решила показать. База хранит то, что программа на самом деле записала. Между ними бывают расхождения:

Такие проверки — серый ящик из раздела 02: код не читаем, но знаем, где и как хранятся данные. В реальных проектах доступ к базе тестового стенда обычно дают по запросу; к рабочей базе — почти никогда, и это правильно.

02

SQLite и DB Browser

SQLite — база данных в одном файле, без сервера. «Задачник» хранит всё в tasker.db рядом с tasker.py. DB Browser for SQLite открывает такой файл и показывает таблицы, данные и результат запросов.

Открывайте базу только для чтения: Файл → «Открыть БД только для чтения…» (Ctrl+Shift+O). Если открыть обычно и начать править ячейки, DB Browser держит изменения в незавершённой транзакции, и «Задачник» в это время может получить ошибку «database is locked». Внизу окна должно быть написано «Только для чтения».

Вкладки DB Browser:

DB Browser for SQLite, файл tasker.db: вкладка Browse Data, таблица tasks с 11 строками и столбцами id, owner_id, title, due, priority, status; справа панель «Схема БД» с таблицами sessions, tasks, users; внизу надпись «Только для чтения»

После действия в «Задачнике» данные в DB Browser сами не обновляются: на вкладке Browse Data нажмите кнопку обновления (две зелёные стрелки) или выполните запрос заново.

03

Схема базы «Задачника»

ТаблицаСтолбцыЧто хранит
usersid, login, password, createdПользователи
sessionstoken, user_id, createdДействующие сессии и токены API; одна строка — один вход
tasksid, owner_id, title, due, priority, status, created, updatedЗадачи; owner_id — id пользователя из users

Даты хранятся текстом: срок — 2026-10-29, время создания и изменения — 2026-10-29 13:07:50. Статус — код: new, in_progress, done (на экране — «Новая», «В работе», «Готово»). Пустой срок — NULL.

04

SQL для проверок

Тестировщику хватает чтения: SELECT и несколько дополнений. Изменять данные запросами (UPDATE, DELETE) в этом курсе не нужно — для этого есть интерфейс, API и --reset.

Что нужноЗапрос
Все задачи пользователя 2SELECT * FROM tasks WHERE owner_id = 2;
Только нужные столбцы, по порядкуSELECT id, title, due FROM tasks ORDER BY due;
Поиск по части названияSELECT * FROM tasks WHERE title LIKE '%отчёт%';
Задачи без срокаSELECT * FROM tasks WHERE due IS NULL;
Срок раньше сегодняшнего дняSELECT * FROM tasks WHERE due < date('now', 'localtime');
Сколько всегоSELECT COUNT(*) FROM tasks WHERE owner_id = 1;
Сколько в каждой группеSELECT status, COUNT(*) FROM tasks GROUP BY status;
Данные из двух таблицSELECT u.login, t.title FROM tasks t JOIN users u ON u.id = t.owner_id;
Последняя созданная задачаSELECT * FROM tasks ORDER BY id DESC LIMIT 1;

Пример — сколько задач у каждого пользователя в каждом статусе (JOIN нужен, чтобы вместо номера пользователя видеть логин):

Вкладка Execute SQL: запрос SELECT u.login, t.status, COUNT(*) AS tasks FROM tasks t JOIN users u ON u.id = t.owner_id GROUP BY u.login, t.status ORDER BY u.login, t.status; результат — ivan done 2, ivan in_progress 2, ivan new 4, maria in_progress 1, maria new 2; внизу «Execution finished without errors. Result: 5 строк возвращено»

То же в Linux консольной программой sqlite3 (Debian 13, sqlite3 3.46):

$ sqlite3 -header -column tasker.db "SELECT id, title, status, priority FROM tasks WHERE owner_id = 2;"
id  title                                   status       priority
--  --------------------------------------  -----------  --------
9   Записаться к врачу                      new          2
10  Пароль от Wi-Fi переговорной: Neva2026  new          1
11  План командировки в Казань              in_progress  3

Внимание к LIKE и регистру: в SQLite LIKE не различает регистр только латинских букв, а '%Отчёт%' и '%отчёт%' для кириллицы — разные запросы. Если проверяете поиск приложения запросом к базе, помните об этом, чтобы не принять особенность SQLite за дефект программы или наоборот.

05

Как проверять операцию по базе

Схема одна для любой операции: до — действие — после.

  1. До: запросом записать состояние, которое операция должна изменить: число строк, значения полей, время updated.
  2. Действие: выполнить операцию в интерфейсе или через API, запомнить время.
  3. После: тем же запросом получить новое состояние и сравнить с ожидаемым по требованиям.
ОперацияЧто проверить в базе
СозданиеПоявилась ровно одна строка; поля совпадают с введёнными (пробелы по краям, регистр, кириллица); правильный владелец; created и updated заполнены
ИзменениеИзменились только нужные поля; updated стал новее, created не изменился
Смена статусаНовый код статуса; другие поля не тронуты
УдалениеСтроки нет (или есть отметка об удалении, если так в требованиях)
Счётчики и итогиЧисло на экране равно COUNT(*) по тем же условиям, что в требованиях
РегистрацияСтрока пользователя; как хранится пароль (требование Т9.1)
Вход и выходПри входе появляется строка в sessions, при выходе — исчезает

В баг-репорт о данных вставляйте запрос и его результат до и после — разработчик повторит их у себя.

06

Журнал сервера

Журнал (лог) — записи сервера о том, что он делал. «Задачник» пишет журнал в консоль и в файл tasker.log: время, метод, адрес и код ответа каждого запроса.

2026-10-29 13:07:50 Задачник 1.0: http://127.0.0.1:8000 — остановить: Ctrl+C
2026-10-29 13:07:53 GET /api/tasks 401
2026-10-29 13:07:53 POST /api/login 200
2026-10-29 13:07:54 GET /api/tasks?status=in_progress 200

Когда сервер отвечает 500, в журнал пишется трассировка (traceback) — цепочка вызовов, на которой программа упала. Пример из вымышленного интернет-магазина на Python:

2026-11-12 14:31:07 POST /api/cart/apply-coupon — внутренняя ошибка
Traceback (most recent call last):
  File "shop/server.py", line 210, in dispatch
    self.api(method, url.path)
  File "shop/cart.py", line 88, in apply_coupon
    discount = coupon["percent"] / 100 * cart.total
               ~~~~~~^^^^^^^^^^^
KeyError: 'percent'
2026-11-12 14:31:07 POST /api/cart/apply-coupon 500

Как читать: последняя строка трассировки — тип ошибки и подробность (KeyError: 'percent' — у купона нет поля «percent»); строки выше — где именно, от общего к частному. Исправлять тестировщику не нужно, но первую и последнюю строки трассировки вставляют в баг-репорт: по ним разработчик сразу найдёт место.

Как найти нужную запись: отметьте время действия (в Network DevTools у запроса есть время, в curl — заголовок Date), откройте журнал и ищите строки за эту секунду.

# Windows PowerShell: последние 20 строк и строки с ошибками
Get-Content tasker.log -Tail 20 -Encoding utf8
Select-String -Path tasker.log -Pattern "ошибка", "Traceback" -Encoding utf8
# Linux
tail -n 20 tasker.log
grep -n -A 12 "внутренняя ошибка" tasker.log

В Windows PowerShell 5.1 указывайте -Encoding utf8, иначе русские буквы журнала будут искажены. Журнал можно открыть и Блокнотом — он понимает UTF-8.

07

Тестовые данные

Результат проверки зависит от данных, поэтому их готовят так же внимательно, как шаги:

После прогона данные возвращают в исходное состояние — иначе следующий прогон начнётся с «грязной» базы, и его результаты нельзя будет сравнить.

Ключевые выводы раздела

Запомните главное

  • База показывает, что программа записала на самом деле; расхождение с экраном — дефект
  • Базу работающего приложения открывают только для чтения
  • Проверка по базе: запрос до, действие, тот же запрос после
  • При изменении записи updated должен стать новее, остальные поля — не измениться
  • Ошибку 500 ищут в журнале по времени запроса; последняя строка трассировки — тип ошибки
  • Тестовые данные: известное начальное состояние, узнаваемые значения, никаких настоящих персональных данных
Практические задания — на учебном портале. Задания, критерии оценивания, сдача работ и оценки преподавателя — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Раздел 09: Тестирование API вручную Все разделы Раздел 11: Тестовый процесс