Unit-тестирование в СУБД Oracle

Курс посвящён практикам и инструментам unit-тестирования PL/SQL-кода в Oracle Database. Рассматриваются организация тестовой среды, написание и запуск тестов, работа с тестовыми данными, а также интеграция тестирования в CI/CD и анализ качества кода.

1. Основы unit-тестирования PL/SQL и стратегия тестов

Основы unit-тестирования PL/SQL и стратегия тестов

Unit-тестирование в Oracle — это практика, при которой небольшие фрагменты логики (обычно функции/процедуры/методы пакетов) проверяются автоматически, быстро и изолированно. Цель — получать быструю обратную связь при изменениях в PL/SQL-коде и снижать риск регрессий.

В этом курсе мы будем опираться на идеи xUnit-подхода и на популярный фреймворк utPLSQL.

Полезные источники:

  • utPLSQL (официальный сайт)
  • utPLSQL (GitHub репозиторий)
  • Oracle Database PL/SQL Language Reference (документация Oracle)
  • The Practical Test Pyramid (Martin Fowler)
  • Что такое unit-тест именно в СУБД

    Unit-тест проверяет небольшой unit (единицу) логики в контролируемых условиях.

    В PL/SQL в роли unit чаще всего выступают:

  • функция (возвращает значение и идеальна для unit-тестов)
  • процедура (проверяем побочные эффекты: изменения данных, вызовы других процедур, сформированные записи и т.д.)
  • пакет (как модуль: тестируем публичные точки входа)
  • Важно различать уровни тестов:

  • Unit-тесты: быстрые, изолированные, на уровне одной логической единицы.
  • Интеграционные тесты: проверяют взаимодействие нескольких модулей и/или внешних зависимостей (таблицы, очереди, внешние сервисы).
  • End-to-end (реже в чистом виде внутри БД): проверяют целый сценарий «как в проде».
  • В Oracle грань между unit и интеграционным тестом часто проходит по границе зависимостей:

  • если тестируемая логика зависит только от входных параметров и не читает/пишет таблицы — это почти всегда unit
  • если логика активно работает с таблицами, последовательностями, контекстами сессии, временем — тесты становятся ближе к интеграционным
  • Это нормально: в БД значимая часть логики действительно про данные.

    Зачем unit-тесты в PL/SQL

    Unit-тесты в PL/SQL особенно полезны, когда:

  • бизнес-правила реализованы в пакетах, а не только в приложении
  • есть сложные расчёты, проверки, маршрутизация, генерация проводок/документов
  • изменения в схеме и коде происходят часто
  • Практические эффекты:

  • быстрее выявляются ошибки при рефакторинге
  • проще менять код безопасно: тесты становятся «страховочной сеткой»
  • формируется исполняемая документация: что должно происходить в типовых и граничных случаях
  • Что делает тест «хорошим»

    Хороший unit-тест в контексте PL/SQL обычно обладает свойствами:

  • быстрый: запускается за миллисекунды/секунды, а не минуты
  • детерминированный: одинаковый результат при каждом запуске
  • изолированный: минимально зависит от окружения и сторонних данных
  • понятный: по названию и структуре видно, что проверяется и почему
  • проверяет одно утверждение (или одну мысль) и падает с понятным сообщением
  • Антипаттерны:

  • тест «иногда падает» из‑за времени, случайности, параллельных запусков
  • тест зависит от данных, которые «уже лежат в таблице»
  • тест делает слишком много проверок и непонятно, что сломалось
  • Базовая структура теста: Arrange–Act–Assert

    Практичный шаблон для большинства unit-тестов:

  • Arrange — подготовить данные и зависимости (вставить тестовые строки, настроить контекст, подготовить входные параметры).
  • Act — выполнить тестируемое действие (вызвать функцию/процедуру).
  • Assert — проверить результат (возвращаемое значение, изменения в таблице, выброшенную ошибку и т.д.).
  • !Наглядная схема трёх фаз теста

    Выбор фреймворка: почему utPLSQL

    Для PL/SQL unit-тестов нужен инструмент, который:

  • запускает тесты пакетами/наборами
  • даёт ассёрты (утверждения)
  • формирует отчёты (в том числе для CI)
  • позволяет изолировать тесты (setup/teardown, транзакции)
  • utPLSQL — де-факто стандарт в сообществе Oracle для unit-тестирования PL/SQL: он поддерживает аннотации, наборы тестов, репортеры и удобные проверки.

    Минимальный пример: тестируем функцию

    Представим простую функцию в пакете, которая нормализует скидку: не ниже 0 и не выше 50.

    Тестовый пакет на utPLSQL (упрощённо):

    Что важно в примере:

  • тесты не зависят от таблиц — это «чистые» unit-тесты
  • проверяются граничные случаи (null, выход за верхнюю границу)
  • тесты читаются как спецификация поведения
  • Стратегия тестирования PL/SQL: что и как покрывать

    Стратегия нужна, чтобы тестирование не превращалось в набор случайных проверок. В Oracle-проектах особенно важно договориться о границах и приоритетах.

    Принцип пирамиды тестов

    Идея пирамиды: чем ниже уровень теста, тем больше их должно быть и тем быстрее они должны выполняться.

    !Пирамида тестов с акцентом на unit-слой

    Практическая интерпретация для БД:

  • много тестов на вычисления, правила, преобразования (unit)
  • меньше тестов на работу с таблицами, транзакциями, блокировками, триггерами (integration)
  • совсем немного сценарных тестов, максимально похожих на боевое использование
  • Как выбирать «единицу» тестирования в PL/SQL

    Чаще всего тестируют:

  • публичные процедуры/функции пакетов (API пакета)
  • функции, которые реализуют правила и удобно проверяются разными наборами входных данных
  • Реже тестируют напрямую:

  • приватные подпрограммы (обычно лучше тестировать через публичный API; приватные детали можно менять без переписывания тестов)
  • триггеры (их поведение часто лучше проверять интеграционно через DML и проверку результата)
  • Практическое правило: тест должен падать, когда нарушено поведение, а не когда вы поменяли реализацию.

    Приоритизация: что покрывать в первую очередь

    Покрытие тестами стоит начинать с того, где цена ошибки выше:

  • денежные расчёты, лимиты, скидки, налоги, комиссии
  • доступы и проверки прав
  • критичные статусы и переходы состояний
  • сложные ветвления (много if/elsif, исключения)
  • места, где ранее уже были дефекты
  • Изоляция: управление зависимостями

    В PL/SQL зависимостями часто выступают:

  • таблицы и справочники
  • последовательности
  • текущая дата/время (sysdate, systimestamp)
  • параметры сессии и NLS-настройки
  • контекст (sys_context), текущий пользователь
  • внешние вызовы (HTTP, очереди, файловая система)
  • Стратегии изоляции:

  • делайте вычисления «чистыми»: выносите правила в функции без побочных эффектов, а доступ к данным — в отдельный слой
  • передавайте зависимости параметрами (например, «текущую дату»), чтобы тест мог подставить значение
  • фиксируйте окружение теста (например, NLS-настройки) в setup
  • минимизируйте работу тестов с общими таблицами; используйте отдельные тестовые данные
  • Данные для тестов: «минимально достаточно»

    Основная ошибка в БД-тестах — создавать слишком много данных «на всякий случай». Это замедляет прогон и усложняет понимание.

    Рекомендации:

  • создавайте ровно те строки, которые нужны для сценария
  • предпочитайте явные значения (чтобы было понятно, почему ожидается именно такой результат)
  • делайте независимые тесты: каждый тест сам готовит данные и сам их очищает
  • Транзакции и очистка после тестов

    В БД тесты часто меняют данные. Важно не «загрязнять» окружение.

    Подходы:

  • оборачивать тест в транзакцию и откатывать изменения в конце
  • использовать setup/teardown процедуры: подготовить данные перед тестом и удалить после
  • запускать тесты в отдельной схеме или в отдельном тестовом контуре
  • Какой подход выбрать — зависит от политики доступа, объёма данных и ограничений проекта. В рамках курса мы будем рассматривать практику, где тесты максимально автономны и не оставляют следов.

    Именование тестов и читаемость

    Тесты читают чаще, чем пишут — особенно когда что-то сломалось.

    Практичные правила:

  • название теста описывает ожидаемое поведение: что при каких условиях должно быть
  • один тест — одна мысль
  • используйте единый стиль: например, should_<ожидание>_when_<условие> или человекочитаемые фразы в описаниях utPLSQL
  • Примеры хороших формулировок:

  • «Возвращает 0, если скидка не задана»
  • «Ограничивает скидку 50, если передано больше 50»
  • «Выбрасывает ошибку, если счёт закрыт»
  • Типовые сложности PL/SQL-тестов и как их избежать

    Нестабильность из-за времени

    Если логика использует sysdate/systimestamp, тесты могут зависеть от момента запуска.

    Решение:

  • передавайте «текущую дату» параметром
  • или делайте отдельную функцию get_now, которую можно контролировать в тестах (подменой уровня абстракции)
  • Нестабильность из-за NLS и форматов

    Одинаковый код может по-разному интерпретировать даты/числа при разных настройках.

    Решение:

  • используйте явные преобразования с форматами
  • в тестах фиксируйте нужные NLS-параметры на сессию, если это важно для поведения
  • Случайность и последовательности

    dbms_random и последовательности могут делать тесты непредсказуемыми.

    Решение:

  • избегайте случайности в unit-тестах
  • возвращайте значения из функций так, чтобы их можно было предсказать и проверить
  • если нужен идентификатор — используйте заранее подготовленные значения или контролируемые механизмы генерации
  • Что считать «готовностью» кода с точки зрения тестов

    Минимальный «Definition of Done» для PL/SQL-модуля в рамках unit-тестирования обычно включает:

  • тесты на основные ветки бизнес-логики и ключевые ошибки
  • тесты на граничные значения
  • отсутствие зависимости тестов от «случайных» данных в среде
  • возможность запускать тесты автоматически (локально и в CI)
  • Итоги

  • Unit-тесты в Oracle чаще всего пишутся для функций/процедур пакетов и проверяют поведение маленьких фрагментов логики.
  • Базовый шаблон теста — Arrange–Act–Assert.
  • Стратегия тестирования в PL/SQL строится вокруг границ зависимостей: чем меньше зависимостей — тем ближе тест к unit.
  • Основные причины нестабильных тестов в БД — время, NLS-настройки, случайность и общие данные.
  • utPLSQL — практичный выбор для автоматизации unit-тестов в Oracle.
  • 2. Подготовка тестовой среды: схемы, права, изоляция, транзакции

    Подготовка тестовой среды: схемы, права, изоляция, транзакции

    Unit-тесты в PL/SQL ценны только тогда, когда они воспроизводимы и изолированы. В прошлой статье мы говорили о стратегии и качестве тестов (быстрые, детерминированные, независимые). На практике эти свойства почти всегда упираются в то, как устроена тестовая среда в Oracle: где живут тесты, какими правами они выполняются, как откатываются изменения и как исключить влияние «чужих» данных.

    Цель этой статьи — собрать рабочий набор подходов, чтобы:

  • тесты можно было запускать многократно с одинаковым результатом
  • тесты не портили данные и не зависели от данных «в базе»
  • права были минимально необходимыми, а не «дайте DBA»
  • поведение в транзакциях было предсказуемым
  • Полезные ссылки:

  • utPLSQL (официальный сайт)
  • utPLSQL (GitHub репозиторий)
  • Документация Oracle: CREATE USER
  • Документация Oracle: GRANT
  • Документация Oracle: ALTER SESSION
  • Базовые принципы тестовой среды в Oracle

    Сразу договоримся о терминах:

  • Схема — набор объектов БД (таблицы, пакеты, представления), принадлежащий пользователю. В Oracle «пользователь» и «схема» тесно связаны: обычно схема называется так же, как пользователь-владелец.
  • Системная привилегия — право на действие уровня базы (например, create session, create procedure).
  • Объектная привилегия — право на конкретный объект (например, execute на пакет, select на таблицу).
  • Роль — контейнер для привилегий, который можно выдавать пользователям.
  • Практичные принципы:

  • Изоляция: тесты должны минимально зависеть от глобальных данных и состояния.
  • Повторяемость: тест можно запустить 100 раз — результат одинаковый.
  • Минимальные права: тестовый пользователь имеет ровно те права, которые нужны для тестов.
  • Контролируемые транзакции: тесты не оставляют «следов».
  • Организация схем: варианты и компромиссы

    Одна схема для всего

    Идея: приложение, данные и тесты живут в одной схеме.

    Плюсы:

  • проще стартовать (минимум пользователей/грантов)
  • Минусы:

  • тесты легко получают лишние права «по наследству»
  • тесты сложнее изолировать от боевых данных (особенно в общих контурах)
  • выше риск случайно модифицировать не те объекты
  • Такой вариант допустим для учебных задач и очень маленьких проектов, но плохо масштабируется.

    Раздельные схемы: рекомендуемая базовая модель

    Типичная схема для реальных проектов:

  • APP — схема приложения (пакеты/таблицы бизнес-логики)
  • APP_TEST — схема, где лежат тестовые пакеты utPLSQL
  • UT3 (или отдельная схема под фреймворк) — где установлены объекты utPLSQL (зависит от политики установки)
  • !Разделение схем и направленность выдачи прав

    Плюсы:

  • тесты работают как «внешний потребитель» API приложения
  • проще контролировать права и уменьшать риск
  • проще запускать тесты в CI и в общих средах
  • Минусы:

  • чуть больше административной настройки (пользователи, роли, гранты)
  • Права доступа: как сделать минимально достаточный набор

    Какие права обычно нужны тестовой схеме

    Минимальный набор зависит от того, что делают тесты.

    Чаще всего APP_TEST требуется:

  • системные привилегии:
  • - create session - create procedure (чтобы создавать тестовые пакеты)
  • объектные привилегии:
  • - execute на тестируемые пакеты в APP - execute на объекты utPLSQL (обычно это пакет запуска и ассёрты)

    Если тесты вставляют данные в таблицы приложения (это уже ближе к интеграционным тестам), понадобятся:

  • insert/update/delete/select на конкретные таблицы или представления
  • Ключевая идея: выдавайте доступ не «на всё», а на конкретные объекты.

    Пример: создание пользователей и роль для тестов

    Ниже пример шаблонного скрипта. В реальном проекте названия tablespace и политика паролей будут другими.

    Важно:

  • Если вы выдаёте права через роль, помните: в PL/SQL (внутри хранимых процедур) роли часто не учитываются так, как в обычном SQL. Для надежности права на объекты, которые реально используются внутри PL/SQL, обычно выдают напрямую (или используют корректно настроенные definer rights). Это особенно критично для кода приложения, но для тестового пользователя чаще достаточно объектных execute на публичный API.
  • Definer rights и invoker rights: почему тест может «не видеть» таблицу

    В Oracle у пакетов/процедур есть режим выполнения:

  • Definer rights (по умолчанию): код выполняется с правами владельца (схемы APP).
  • Invoker rights (authid current_user): код выполняется с правами вызывающего пользователя (например, APP_TEST).
  • Практическое следствие:

  • если пакет APP использует definer rights, тесту обычно достаточно execute на пакет
  • если пакет APP использует invoker rights, тестовому пользователю понадобятся дополнительные права на таблицы/представления и другие объекты, которые пакет читает/меняет
  • Мини-пример объявления invoker rights:

    Рекомендация для тестируемости:

  • тестируйте через публичный API пакета
  • явно решайте, где вам нужен invoker rights, а где лучше оставить definer rights
  • не «лечите» падающий тест выдачей широких прав, сначала выясните режим прав и реальные зависимости
  • Установка и доступ к utPLSQL

    utPLSQL можно ставить по-разному (зависит от версии, политики безопасности и того, общий ли это сервер):

  • установка в отдельную схему (часто удобно)
  • установка в схему тестов
  • установка централизованно на сервере, а тестовые схемы получают только execute
  • У utPLSQL есть официальные инструкции установки и примеры конфигураций (следуйте им в первую очередь):

  • utPLSQL Documentation (latest)
  • utPLSQL install guide (GitHub)
  • Ключевая цель настройки: тестовый пользователь должен иметь возможность запускать тесты и получать отчёт, но не должен иметь лишних административных прав.

    Изоляция данных: как не зависеть от «того, что уже лежит в таблицах»

    В Oracle тесты часто затрагивают таблицы, и это основная причина нестабильности. Есть несколько базовых стратегий.

    Транзакционный откат

    Идея: тест делает insert/update/delete, а в конце всё откатывается rollback.

    Плюсы:

  • очень быстро
  • не требует явной очистки таблиц
  • Ограничения:

  • DDL (например, create table, truncate) делает неявный commit и ломает идею «откатим всё»
  • автономные транзакции не откатываются вместе с основным тестом
  • Практика:

  • избегайте DDL внутри тестов
  • старайтесь, чтобы тесты работали в рамках одного соединения и одной транзакции
  • используйте возможности utPLSQL по управлению транзакциями (в том числе автоматический откат после теста, если он включён вашей конфигурацией)
  • Savepoint для частичного отката внутри теста

    Если внутри теста нужно выполнить несколько шагов и откатить только часть действий, используйте savepoint:

    Setup/teardown: явная подготовка и очистка

    Идея: каждый тест сам создаёт минимальные данные и сам же их удаляет.

    Плюсы:

  • прозрачно и контролируемо
  • хорошо работает, когда тесты должны проверять commit-поведение
  • Минусы:

  • выше риск забыть очистку
  • дольше, чем чистый rollback, если много DML
  • Практика:

  • создавайте ровно те строки, которые нужны
  • удаляйте по ключам тестовых данных (а не «чистим всю таблицу»)
  • Глобальные временные таблицы

    Global Temporary Table (GTT) — таблица, структура которой постоянна, но данные в ней сессионные (или транзакционные) и не видны другим сессиям.

    Когда полезно:

  • для промежуточных результатов в тестах
  • для изоляции данных между параллельными прогонами
  • Важно понимать:

  • GTT создаётся один раз (DDL), но наполнение идёт DML
  • режим очистки задаётся при создании: on commit delete rows или on commit preserve rows
  • Пример:

    Транзакции в тестах: правила, которые спасают от «магии»

    Транзакция в Oracle — это набор изменений, который завершается commit (зафиксировать) или rollback (откатить).

    Проблемы, которые чаще всего ломают тестовую изоляцию:

  • Неявные commit из-за DDL: многие DDL-операции фиксируют транзакцию до и после выполнения.
  • Автономные транзакции: изменения, сделанные внутри pragma autonomous_transaction, живут отдельно и не откатываются вместе с тестом.
  • Смешение ответственности: тест проверяет бизнес-логику и одновременно пытается «руками» управлять сложными транзакционными сценариями без чёткой модели.
  • DDL в тестах: почему это почти всегда плохая идея

    Примеры DDL:

  • create table, alter table, drop table
  • truncate table
  • Даже если вы планировали откатить тест, DDL может зафиксировать изменения и оставить мусор. Поэтому:

  • структуру (таблицы/типы/пакеты) подготавливайте миграциями до прогона
  • тесты должны в основном делать DML и откатываться
  • Автономные транзакции: как они влияют на тесты

    Автономная транзакция часто используется для логирования:

    Если тест вызывает такой код:

  • запись в log_table останется, даже если тест откатится
  • Что делать:

  • в unit-тестах стараться не проверять логирование через автономные транзакции
  • если нужно, делайте явную очистку лог-таблиц по ключу теста
  • рассмотреть архитектурное разделение: бизнес-логика отдельно, побочные эффекты (лог, очереди) отдельно
  • Фиксация окружения сессии: NLS, часовой пояс, контекст

    Тест может быть детерминированным только если окружение стабильно.

    NLS-настройки

    Одинаковый код может по-разному преобразовывать строки в даты/числа при разных NLS. Если тесты зависят от форматирования, в подготовке тестового набора фиксируйте параметры:

    Документация по параметрам и синтаксису:

  • Документация Oracle: ALTER SESSION
  • Рекомендация:

  • по возможности не завязывайтесь на NLS в логике (используйте явные форматы)
  • если завязка неизбежна, фиксируйте параметры в setup тестов
  • Контекст сессии

    Если приложение использует контекст (например, «текущий клиент», «роль», «канал»), тест должен уметь его выставить и сбросить. Для этого обычно используют:

  • dbms_session.set_context (если настроен application context)
  • отдельные процедуры в API приложения вида set_current_tenant, set_security_context
  • Главное правило: тест не должен зависеть от того, что контекст «как-то сам уже выставлен».

    Параллельный запуск тестов и конфликты

    В CI и на больших проектах тесты часто запускают параллельно. Типовые источники конфликтов:

  • общие «тестовые» ключи (например, всегда вставляем id = 1)
  • одни и те же строки справочников, которые тесты пытаются менять
  • блокировки из-за долгих транзакций
  • Практика, которая помогает:

  • делайте тестовые данные уникальными (например, ключи через отдельную тестовую последовательность)
  • не меняйте «общие» справочники, если это не цель теста
  • держите транзакции короткими
  • Мини-чеклист готовности тестовой среды

  • Есть отдельная схема для тестов или чётко выделенная область в одной схеме.
  • Тестовый пользователь имеет минимальные права: create session, create procedure, execute на API.
  • Понятно, какие пакеты definer rights, а какие invoker rights.
  • Тесты не используют DDL во время прогона.
  • Выбрана стратегия очистки: rollback или teardown.
  • Зафиксированы критичные параметры окружения (NLS/контекст), если они влияют на поведение.
  • Итоги

  • Правильная тестовая среда в Oracle — это сочетание разделения схем, минимальных прав и контролируемых транзакций.
  • Раздельные схемы APP и APP_TEST обычно дают лучший контроль и безопасность.
  • Definer rights и invoker rights напрямую влияют на то, какие права нужны тестовому пользователю.
  • Самая надёжная изоляция для быстрых тестов — DML + rollback, но DDL и автономные транзакции требуют особого внимания.
  • Стабильность тестов часто зависит от NLS и контекста сессии — их нужно фиксировать в setup.
  • 3. Инструменты: utPLSQL, SQL Developer и вспомогательные фреймворки

    Инструменты: utPLSQL, SQL Developer и вспомогательные фреймворки

    Из предыдущих статей у нас уже есть два ключевых слоя:

  • стратегия unit-тестирования PL/SQL: что считать unit-тестом, как писать детерминированные проверки и где проходит граница зависимостей
  • тестовая среда: схемы, права, изоляция данных, транзакции и факторы нестабильности (DDL, автономные транзакции, NLS)
  • Теперь добавим третий слой: инструменты, которые превращают эти идеи в регулярную практику. В Oracle-проектах обычно есть два режима работы:

  • локально разработчик пишет код и запускает тесты из IDE (часто SQL Developer)
  • в CI тесты запускаются без участия человека из командной строки, результаты публикуются в виде отчётов
  • В этой статье разберём:

  • что именно предоставляет utPLSQL и как им пользоваться в базе
  • как практично использовать SQL Developer для разработки и запуска тестов
  • какие вспомогательные инструменты обычно окружают utPLSQL: командный запуск, миграции схемы, отчётность, покрытие
  • Полезные источники:

  • utPLSQL (официальный сайт)
  • utPLSQL (GitHub репозиторий)
  • utPLSQL CLI (GitHub репозиторий)
  • Oracle SQL Developer (страница продукта)
  • Oracle SQLcl (страница продукта)
  • Liquibase (официальный сайт)
  • Flyway (официальный сайт)
  • !Общая картина того, как utPLSQL используется локально и в CI

    utPLSQL как основа unit-тестирования в Oracle

    utPLSQL — это фреймворк в стиле xUnit, установленный внутри Oracle Database и запускающий тесты, написанные на PL/SQL.

    Важно понимать две роли utPLSQL:

  • раннер тестов: находит тестовые пакеты, выполняет тестовые процедуры, управляет жизненным циклом
  • библиотека ассёртов и матчерей: позволяет выражать ожидания в читаемой форме, например ut.expect(...).to_equal(...)
  • Из чего состоит тест на utPLSQL

    Тесты обычно оформляются как PL/SQL-пакеты в тестовой схеме (например, APP_TEST). Тесты помечаются аннотациями в комментариях вида --%suite, --%test.

    Типовой минимум:

  • --%suite(<название набора>) на уровне пакета
  • --%test(<описание>) на уровне тестовой процедуры
  • Пример (схематично):

    Связь с предыдущими статьями:

  • чтобы тест был детерминированным, он должен сам подготовить входные условия (Arrange) и не зависеть от случайных данных
  • чтобы тест был изолированным, он не должен оставлять изменения (обычно через транзакционный откат или teardown)
  • Жизненный цикл тестов: setup и teardown

    utPLSQL поддерживает хуки жизненного цикла. На практике это главный механизм, который помогает стандартизировать подготовку и очистку данных.

    Что обычно используют:

  • подготовка общих данных для набора тестов
  • подготовка данных перед каждым тестом
  • очистка после теста
  • Это помогает придерживаться принципа: каждый тест независим и самодостаточен.

    Запуск тестов из базы (самый базовый способ)

    Если у вас есть доступ к схеме с utPLSQL и тестами, тесты можно запускать из SQL-окна:

    Часто нужно ограничить запуск конкретным набором (например, пакетом) или схемой. Конкретные варианты зависят от версии utPLSQL и принятой структуры, поэтому правильнее сверяться с документацией вашей версии:

  • utPLSQL Documentation (страница документации)
  • Ключевая идея неизменна: utPLSQL исполняет тестовые пакеты и возвращает отчёт через выбранный репортёр.

    Репортёры: зачем они нужны

    Репортёр определяет, в каком формате будут выведены результаты тестов.

    Обычно нужны два класса форматов:

  • человекочитаемые (для локального запуска)
  • машиночитаемые (для CI, публикации артефактов, интеграций)
  • На практике самые востребованные сценарии:

  • локально: читаемый текстовый отчёт в консоль
  • в CI: отчёт в стиле xUnit/JUnit XML, который понимают многие CI-системы и интерфейсы тест-репортинга
  • Именно репортёры связывают прогон тестов в БД с внешним миром (IDE, CI, отчётность).

    Покрытие PL/SQL-кода

    Покрытие отвечает на вопрос: какие участки PL/SQL кода были выполнены во время тестов. Это не заменяет качество тестов, но помогает:

  • находить «слепые зоны» (где тестов нет)
  • контролировать регресс в покрытии при крупных изменениях
  • Важные ограничения, перекликающиеся со статьёй про среду:

  • сбор покрытия может замедлять прогон
  • некоторые действия (например, DDL и автономные транзакции) усложняют предсказуемость поведения тестов и анализа
  • SQL Developer как рабочее место для тестов

    SQL Developer — это IDE для работы с Oracle Database: подключение к схемам, редактирование объектов, запуск скриптов, просмотр ошибок компиляции.

    В контексте unit-тестов SQL Developer чаще всего нужен не как «тестовый фреймворк», а как удобная оболочка вокруг utPLSQL.

    Практичный минимум настроек для запуска тестов

    Чтобы запуск тестов был удобным и предсказуемым:

  • держите отдельные подключения для APP и APP_TEST, чтобы не запускать тесты «не тем пользователем»
  • включайте вывод сообщений, если вы используете dbms_output в отладочных целях
  • используйте окно ошибок компиляции, чтобы быстро исправлять проблемы в тестовых пакетах
  • Пример типовых команд в worksheet:

    Быстрый цикл: редактирование, компиляция, запуск

    SQL Developer удобен тем, что даёт быстрый цикл:

  • редактировать пакет тестов
  • скомпилировать
  • тут же увидеть ошибки компиляции (если есть)
  • запустить ut.run и увидеть результат
  • Это напрямую помогает выполнять принцип из первой статьи: быстрая обратная связь.

    О чём SQL Developer не «подумает» за вас

    SQL Developer не решает архитектурные проблемы тестируемости:

  • если тесты зависят от данных, которые «уже лежат в таблицах», IDE не сделает их стабильными
  • если код использует sysdate без контроля времени, IDE не сделает тесты детерминированными
  • если внутри тестов выполняется DDL и происходят неявные commit, IDE не сохранит изоляцию
  • Поэтому SQL Developer — это инструмент комфорта, а utPLSQL и корректная тестовая среда — инструменты надёжности.

    Командный запуск: utPLSQL CLI и SQLcl

    Как только вы хотите запускать тесты в CI, вам нужен безынтерактивный запуск.

    Есть два распространённых подхода.

    utPLSQL CLI

    utPLSQL CLI — отдельный инструмент, который подключается к Oracle Database, запускает utPLSQL и сохраняет отчёты в нужных форматах.

    Зачем он нужен:

  • одинаково работает на сервере CI и локально
  • удобно сохраняет отчёты в файлы (например, JUnit XML)
  • облегчает интеграцию в пайплайн сборки
  • Источник:

  • utPLSQL CLI (GitHub репозиторий)
  • Практический принцип: логика тестов живёт в БД, а CLI лишь управляет запуском и выводом результатов.

    SQLcl как универсальный раннер скриптов

    SQLcl — это командная утилита Oracle для выполнения SQL и PL/SQL скриптов.

    Типовой сценарий:

  • CI выполняет скрипт деплоя (накатывает изменения)
  • затем выполняет скрипт запуска тестов, который вызывает ut.run и печатает или сохраняет результат
  • Источник:

  • Oracle SQLcl (страница продукта)
  • SQLcl особенно полезен, если вы уже стандартизировали проект на «все операции делаем скриптами», а не только тесты.

    Вспомогательные фреймворки вокруг utPLSQL

    utPLSQL отвечает за тесты и ассёрты, но для полноценного процесса обычно нужны ещё инструменты вокруг.

    Миграции схемы: Liquibase и Flyway

    Большая часть проблем «у меня локально тесты проходят, а в CI нет» связана с тем, что среда отличается: разные версии схемы, не те объекты, не те зависимости.

    Инструменты миграций решают задачу: привести схему к ожидаемому состоянию перед запуском тестов.

    Два популярных инструмента:

  • Liquibase (официальный сайт)
  • Flyway (официальный сайт)
  • Как это связывается с тестами:

  • миграции поднимают нужную структуру и код
  • затем запускаются utPLSQL тесты
  • результат тестов становится воспроизводимым, потому что схема воспроизводима
  • Генерация и подготовка тестовых данных

    Здесь важно не «чем генерировать», а как не сломать детерминизм.

    Практичный набор подходов:

  • хранить минимальные фикстуры в виде SQL-скриптов insert с явными значениями
  • использовать setup/teardown в utPLSQL вместо ручной очистки «всей таблицы»
  • избегать случайности в данных, если она не является целью теста
  • Если данные должны быть уникальными (например, для параллельного прогона), делайте уникальность контролируемой:

  • отдельная тестовая последовательность
  • префиксы в строковых ключах (например, TEST_<run_id>_...)
  • Это напрямую продолжает идеи из статьи про изоляцию.

    Логирование и диагностика падений

    Когда тест падает, важно быстро понять почему.

    Полезные практики:

  • выводить в сообщение ассёрта диагностически значимые значения (что ожидали и что получили)
  • использовать стандартный стек ошибок Oracle (например, через dbms_utility.format_error_stack), если вы пишете собственные обработчики исключений
  • не полагаться на «посмотрю в таблице логов», если логирование реализовано автономными транзакциями и загрязняет среду
  • Мини-рекомендации по выбору набора инструментов

    Если вы строите процесс с нуля, практичный стартовый набор выглядит так:

  • utPLSQL в базе как стандарт тестов
  • SQL Developer для разработки и локальных прогонов
  • utPLSQL CLI или SQLcl для CI
  • Liquibase или Flyway для приведения схемы к версии, которая соответствует тестам
  • И главный принцип, связывающий все статьи курса:

  • инструменты не исправляют плохую изоляцию и некомпактные тесты, но они делают правильные практики регулярными и автоматизируемыми
  • 4. Проектирование тестируемого PL/SQL: пакеты, зависимости, моки и стабы

    Проектирование тестируемого PL/SQL: пакеты, зависимости, моки и стабы

    Unit-тесты в Oracle становятся быстрыми, детерминированными и изолированными не только благодаря utPLSQL и правильно настроенной среде, но и благодаря тому, как вы проектируете PL/SQL-код.

    В прошлых материалах курса мы уже разобрали:

  • зачем нужны unit-тесты и как мыслить уровнями тестирования
  • как подготовить среду: схемы, права, транзакции, NLS и изоляцию
  • какие инструменты обычно используют: utPLSQL, SQL Developer, CLI/SQLcl
  • Теперь сделаем следующий практический шаг: научимся проектировать пакеты и зависимости так, чтобы тесты писать было легко, а не больно.

    Полезные источники:

  • utPLSQL Documentation
  • utPLSQL GitHub
  • Oracle Database PL/SQL Language Reference
  • Что в PL/SQL делает код нетестируемым

    Большинство проблем с тестированием в БД возникает из-за неявных зависимостей. В PL/SQL они часто скрыты в таких местах:

  • время: прямой вызов sysdate/systimestamp
  • контекст: sys_context(...), user, параметры сессии
  • I/O и внешние системы: HTTP-запросы, очереди, файловая система
  • доступ к данным: прямые select/insert/update/delete “внутри бизнес-логики”
  • глобальное состояние: пакетные переменные, которые “помнят” прошлый тест
  • автономные транзакции, которые оставляют следы даже при rollback
  • Если зависимость не контролируется тестом, тест становится:

  • нестабильным
  • медленным
  • требовательным к окружению
  • Значит, задача проектирования тестируемого PL/SQL — сделать зависимости явными и заменяемыми.

    Принцип: разделяйте вычисления и взаимодействие с миром

    Для unit-тестов идеальна логика, которая зависит только от входных параметров и возвращает результат без побочных эффектов. В Oracle-проектах это редко бывает “чисто”, но к этому можно приблизиться.

    Практичная схема разделения:

  • Доменная логика: вычисления, правила, проверки, маршрутизация.
  • Инфраструктурные зависимости: время, генерация идентификаторов, доступ к таблицам, внешние вызовы.
  • !Схема показывает, что бизнес-пакет зависит от абстракций, а в тестах зависимости подменяются

    Ключевая идея: бизнес-пакет должен зависеть не от “мира”, а от прослоек, которые можно заменить тестовыми двойниками.

    Как проектировать пакеты: API, ответственность, границы

    Делайте пакет модулем с ясным публичным API

    Пакет в Oracle часто является естественной единицей тестирования. Чтобы тесты были устойчивыми:

  • ограничивайте публичный API тем, что является контрактом
  • держите детали реализации приватными (в теле пакета)
  • тестируйте поведение через публичные процедуры/функции
  • Практический эффект: тесты меньше ломаются при рефакторинге.

    Разделяйте ответственность (внутри БД это особенно важно)

    Частая ошибка — пакет “делает всё”: читает таблицы, считает, логирует, ходит во внешний сервис, коммитит.

    Удобнее для тестов, когда ответственность разнесена:

  • _api или _service: бизнес-операции и правила
  • *_repo: операции чтения/записи в таблицы (data access)
  • *_gateway: интеграции (HTTP, очереди)
  • clock: время
  • Это не “архитектура ради архитектуры”: это способ управлять зависимостями.

    Тестовые двойники: стабы, моки, фейки, шпионы

    Термины часто путают, поэтому договоримся о смыслах.

  • Стаб: упрощённая реализация зависимости, которая возвращает заранее заданные значения.
  • Фейк: упрощённая, но работающая реализация (например, хранит данные в тестовой таблице или в памяти пакета).
  • Шпион: двойник, который записывает факты взаимодействия (какие параметры передали, сколько раз вызвали).
  • Мок: двойник, для которого вы заранее задаёте ожидания вызовов, а затем проверяете, что они выполнены.
  • В PL/SQL чаще всего реально применяют стабы и шпионы, потому что они проще и надёжнее. Моки тоже возможны, но их часто реализуют как “ручные” (через пакетные переменные), а не как магию фреймворка.

    Паттерны управления зависимостями в PL/SQL

    Ниже — практичные, распространённые способы сделать зависимости заменяемыми.

    Передавайте зависимость параметром (лучший вариант для функций)

    Это идеальный вариант для детерминизма: зависимость становится частью входа.

    Пример: вместо использования sysdate внутри функции передаём дату параметром.

    Плюсы:

  • легко тестировать
  • нет скрытых зависимостей
  • Минус:

  • не всегда удобно протаскивать параметр через длинную цепочку вызовов
  • Когда “протаскивать” неудобно — используйте следующий паттерн.

    Введите провайдер (обёртку) для времени, контекста и прочих системных вызовов

    Вместо прямого sysdate делаем пакет clock, который можно подменить.

    #### Продовая реализация

    #### Использование в бизнес-коде

    В тесте вы хотите контролировать “текущее время”. Для этого нужен механизм подмены clock. В Oracle есть несколько вариантов подмены, и выбор зависит от политики среды.

    Способы подмены зависимостей в Oracle

    Подмена через синонимы (простой, но требует дисциплины)

    Идея:

  • бизнес-код обращается к зависимости по имени clock
  • в “бою” clock указывает на app.clock
  • в тестовой схеме можно создать синоним clock на app_test.clock_stub
  • Что важно учитывать:

  • это работает, если имена разрешаются через текущую схему/синонимы ожидаемым образом
  • это требует аккуратной организации схем и прав (см. статью про тестовую среду)
  • Подмена через Edition-Based Redefinition (мощно, но сложнее)

    Если в организации используется EBR, можно держать тестовую реализацию зависимости в отдельной edition.

    Это более продвинутый подход, обычно применяемый в больших enterprise-системах.

    Подмена через конфигурацию в пакете (компромисс)

    Идея:

  • бизнес-код вызывает “точку выбора” внутри пакета
  • в тесте вы переключаете реализацию на стаб
  • Пример — “провайдер” времени с возможностью фиксировать дату.

    Плюсы:

  • не требуется сложная инфраструктура
  • легко начать
  • Минусы:

  • появляется глобальное состояние (пакетная переменная)
  • требуется строгая очистка в teardown, иначе тесты начнут влиять друг на друга
  • Если вы используете такой подход, обязательны:

  • сброс состояния (reset_now) после каждого теста
  • запрет на параллельный прогон в одной и той же схеме/сессии без изоляции
  • Разделение доступа к данным: репозитории и минимальные контрактные функции

    Чтобы unit-тесты не превращались в интеграционные, бизнес-логика должна как можно меньше “знать” о таблицах.

    Частый практический компромисс:

  • доменная логика отдельно (можно тестировать почти чисто)
  • доступ к данным через тонкий слой *_repo
  • Пример интерфейса репозитория:

    В реальности pricing_repo читает таблицу. А для unit-тестов вы можете подменить репозиторий стабом, который возвращает нужные значения.

    Внешние интеграции: gateway-пакеты и отказ от прямого HTTP в бизнес-логике

    Если ваш PL/SQL вызывает HTTP (через utl_http) или очередь (AQ), unit-тесты быстро становятся хрупкими.

    Рекомендуемый подход:

  • выносите интеграцию в *_gateway
  • бизнес-код работает с gateway как с зависимостью
  • в unit-тестах подменяете gateway стабом
  • Это не только про тесты: это снижает связность и упрощает сопровождение.

    Шпионы и проверка взаимодействий

    Иногда важно проверить не только результат, но и то, что зависимость была вызвана корректно. Для этого удобно использовать шпион.

    Пример: стаб-шпион как пакет, который запоминает последние параметры.

    Дальше бизнес-код должен быть устроен так, чтобы вместо реального gateway можно было подключить tax_gateway_spy.

    Важно: шпион — это тоже глобальное состояние. Значит, снова требуется жёсткий teardown.

    Definer rights и invoker rights: тестируемость и безопасность

    Из статьи про тестовую среду вы уже знаете, что права выполнения в Oracle критичны.

    Связь с проектированием:

  • если пакет бизнес-логики работает в режиме definer rights (по умолчанию), тестам обычно достаточно execute на API
  • если пакет использует invoker rights (authid current_user), то тестовая схема должна иметь объектные права на все используемые таблицы/представления
  • Это влияет на архитектуру зависимостей:

  • при invoker rights становится сложнее “просто вызвать API”, потому что права должны быть у вызывающего
  • при definer rights проще изолировать права тестов, но нужно внимательнее относиться к безопасности самого API
  • Практическая рекомендация для обучения и большинства прикладных модулей:

  • проектируйте публичный API так, чтобы его можно было тестировать через execute без раздачи широких прав
  • если invoker rights необходим, фиксируйте зависимости (какие объекты нужны) и выдавайте права минимально
  • Управление побочными эффектами: коммиты, автономные транзакции, логирование

    Для unit-тестов полезно, когда тестируемая операция:

  • не делает commit внутри (commit лучше держать на границе сценария)
  • не пишет “вечно” в лог через автономную транзакцию
  • Если автономные транзакции нужны (например, аудит), сделайте их зависимостью:

  • бизнес-логика сообщает “событие”
  • отдельный модуль решает, писать ли в таблицу, в каком режиме, и можно ли это отключить или подменить в тесте
  • Это напрямую связано с изоляцией данных и предсказуемостью отката.

    Как это стыкуется с utPLSQL

    utPLSQL даёт вам:

  • структуру тестов (suite/test, setup/teardown)
  • ассёрты (ut.expect(...))
  • запуск и отчётность
  • Но utPLSQL не отменяет необходимость проектировать зависимости. Чем лучше вы отделили доменную логику и сделали зависимости подменяемыми, тем больше у вас будет:

  • настоящих unit-тестов (быстрых и “без базы”)
  • простых интеграционных тестов (минимальные вставки в таблицы, rollback)
  • Практический чеклист проектирования тестируемого PL/SQL

  • Публичный API пакета мал и стабилен, приватные детали скрыты в body.
  • Время, контекст, внешние вызовы не используются напрямую в доменной логике.
  • Доступ к таблицам вынесен в тонкие *_repo-пакеты.
  • Для внешних интеграций есть *_gateway.
  • Есть понятный способ подменить зависимости в тестах (параметры, провайдеры, синонимы, EBR или конфигурация).
  • Если используются пакетные переменные для тестовых двойников, есть обязательный teardown.
  • Пакеты не делают неожиданных commit, DDL и автономных транзакций внутри “юнитов”, которые вы хотите тестировать изолированно.
  • Итоги

  • Тестируемость PL/SQL в Oracle начинается с проектирования: зависимости должны быть явными и подменяемыми.
  • Самая полезная архитектурная привычка — разделять доменную логику и инфраструктуру (таблицы, время, интеграции).
  • Тестовые двойники в PL/SQL чаще всего реализуются как стабы и шпионы, которые подключаются через слой зависимостей.
  • Выбор между definer rights и invoker rights влияет на то, какими правами должен обладать тестовый пользователь.
  • utPLSQL ускоряет и стандартизирует тестирование, но “магии” не делает: если код завязан на sysdate, контекст и внешние сервисы, тесты будут хрупкими, пока вы не введёте правильные границы.
  • 5. Тестовые данные: фикстуры, генерация, маскирование и очистка

    Тестовые данные: фикстуры, генерация, маскирование и очистка

    Тесты в Oracle ломаются чаще всего не из-за utPLSQL, а из-за данных: в базе уже лежит что-то не то, тесты пересекаются ключами, после падения остался мусор, данные взяли с прода и их нельзя хранить. Поэтому работа с тестовыми данными — это отдельная дисциплина.

    Связь с предыдущими статьями курса:

  • из статьи про стратегию unit-тестирования мы берём цель: быстро, детерминированно, изолированно
  • из статьи про тестовую среду берём правила: минимальные права, управляемые транзакции, избегаем DDL и автономных транзакций, фиксируем NLS/контекст
  • из статьи про инструменты берём практику: setup/teardown в utPLSQL и воспроизводимый запуск в IDE и CI
  • из статьи про проектирование тестируемого PL/SQL берём ключ: минимизировать зависимости от таблиц и внешнего мира, а где зависимости неизбежны — управлять ими
  • В этой статье разберём четыре блока:

  • фикстуры: что это такое и как их организовать
  • генерация: как создавать данные быстро и воспроизводимо
  • маскирование: как не утечь в персональные/коммерческие данные и не нарушить политику безопасности
  • очистка: как гарантированно возвращать базу в исходное состояние
  • Полезные источники:

  • utPLSQL Documentation
  • Oracle Database SQL Language Reference: CREATE TABLE
  • Oracle Database PL/SQL Packages and Types Reference: DBMS_RANDOM
  • Oracle Database SQL Language Reference: STANDARD_HASH
  • !Жизненный цикл тестовых данных и где происходит подготовка и очистка

    Что такое фикстуры и почему они важны

    Фикстура — это заранее подготовленное состояние данных, необходимое для теста.

    В Oracle фикстуры чаще всего выражаются так:

  • строки в таблицах (справочники, документы, статусы)
  • настройки в контексте сессии и NLS
  • значения последовательностей, идентификаторов, ключей
  • Главная цель фикстур — сделать тест самодостаточным: он не должен зависеть от того, что «уже лежит» в базе.

    Виды фикстур, которые реально встречаются в проектах

    | Вид фикстуры | Где хранится | Плюсы | Минусы | Когда подходит | |---|---|---|---|---| | Встроенная (inline) | прямо в теле теста (insert/select) | максимальная близость к тесту | повторение кода, сложно переиспользовать | простые тесты, 1–2 строки | | Скриптовая | SQL-файл с insert | легко переиспользовать, можно версионировать | риск «слишком больших» данных | когда набор данных общий для многих тестов | | Программная | пакет test_data_ с процедурами create_ | единая точка создания данных, меньше копипаста | требует дисциплины и поддержки | средние и большие проекты | | Сессионная | контекст/NLS в setup | стабилизирует окружение | надо гарантировать сброс | когда логика зависит от окружения |

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

    Где и как держать тестовые данные

    Варианты хранения зависят от того, насколько ваши тесты близки к unit или ближе к интеграционным.

  • Если вы тестируете «чистую» функцию без таблиц, фикстуры чаще всего не нужны вообще.
  • Если вы тестируете бизнес-операцию, которая читает/пишет таблицы, фикстуры становятся обязательными.
  • Рекомендуемая практика для Oracle

  • Общие справочники или константы: один небольшой скрипт на схему тестов или общий beforeall.
  • Данные конкретного сценария: создаются в beforeeach или прямо в тесте.
  • Переиспользуемые конструкторы сущностей: пакет-строитель в тестовой схеме.
  • Важно: старайтесь не превращать тестовую БД в «мини-прод» с гигабайтами данных. В unit-тестировании ценность дают не объёмы, а точность и скорость.

    Подготовка данных через utPLSQL lifecycle

    utPLSQL позволяет стандартизировать подготовку и очистку фикстур аннотациями жизненного цикла:

  • --%beforeall и --%afterall для набора тестов
  • --%beforeeach и --%aftereach для каждого теста
  • Пример: общий справочник создаём один раз, а сущность сценария — на каждый тест.

    Ключевые моменты:

  • общие данные делаются маленькими
  • данные сценария создаются на каждый тест
  • очистка идёт по ключам тестовых строк, а не «очистим всю таблицу»
  • Генерация данных: скорость против детерминизма

    Генерация тестовых данных нужна, когда:

  • тестов много и руками писать insert утомительно
  • сущности имеют много колонок и ограничений
  • нужно создавать разные комбинации данных
  • Но генерация легко ломает стабильность тестов, если становится случайной.

    Почему случайность — опасна для unit-тестов

    Если вы используете dbms_random без контроля, вы получите тесты, которые:

  • иногда падают, потому что случайно сгенерировалось «особое» значение
  • тяжело отлаживаются, потому что повторить точный вход сложно
  • Если dbms_random всё же нужен, фиксируйте seed и ограничивайте диапазоны.

    Документация: Oracle Database PL/SQL Packages and Types Reference: DBMS_RANDOM

    Практическая рекомендация: чаще используйте табличные наборы значений и явные константы, а не случайность.

    Пакеты-строители вместо копипаста

    Типичный шаблон для проектов: выделить в тестовой схеме пакет, который создаёт валидные сущности с разумными дефолтами.

    Плюсы:

  • один раз решаете проблему обязательных колонок, ограничений и статусов
  • тесты становятся короче и читаемее
  • легче менять модель данных: правите строителя, а не сотни тестов
  • Уникальные ключи и параллельный запуск

    Когда тесты запускаются параллельно, конфликтуют прежде всего ключи. Есть два подхода:

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

  • завести в тестовой схеме отдельную последовательность (например, app_test.test_seq)
  • получать значения через select app_test.test_seq.nextval into ...
  • в проверках ожидать не конкретный ID, а свойства: not null, существование записи, корректные атрибуты
  • Так вы уменьшаете риск коллизий между тестами, но не делаете тест «рандомным».

    Маскирование тестовых данных

    Главная мысль: лучшие тестовые данные — синтетические. Они не несут юридических и репутационных рисков.

    Но иногда бизнес требует прогонять тесты на «реалистичных» данных: копии прода или интеграционной среды. Тогда включается задача маскирования.

    Что такое маскирование и чем оно отличается от удаления

  • Маскирование заменяет чувствительные поля (ФИО, email, телефон, паспорт, номера карт) на безопасные значения.
  • Удаление просто убирает данные, но часто ломает внешние ключи и тестовые сценарии.
  • Цель маскирования:

  • сохранить структуру данных и связи
  • убрать возможность восстановить реальную личность/коммерческую информацию
  • Принципы безопасного маскирования в Oracle

  • Делайте маскирование необратимым там, где это возможно.
  • Оставляйте формат, если от него зависит логика (например, длина строки, наличие @ в email), но убирайте реальное значение.
  • Маскируйте согласованно: если один и тот же клиент встречается в разных таблицах, маска должна быть одинаковой.
  • Пример: согласованная необратимая маска через хэш

    standard_hash позволяет получить хэш строки. Это необратимо при разумном выборе входа и политики.

    Документация: Oracle Database SQL Language Reference: STANDARD_HASH

    Комментарии к подходу:

  • name становится псевдонимом, который согласован по customer_id
  • email сохраняет формат, но домен тестовый
  • phone заменён на константу, если формат не важен для логики
  • Важно: конкретная политика маскирования всегда должна соответствовать требованиям вашей организации и законодательства. В рамках курса мы фокусируемся на технических принципах, которые помогают делать тестовую базу безопасной.

    Очистка после тестов: стратегии и типовые ловушки

    Очистка — это то, что превращает тест в повторяемый. В Oracle есть несколько стратегий, и выбор зависит от поведения кода.

    Откат транзакции

    Идея: тест делает DML, а затем всё откатывается.

    Плюсы:

  • очень быстро
  • не нужно писать delete
  • Минусы и ловушки:

  • DDL вызывает неявный commit и разрушает изоляцию
  • автономные транзакции не откатываются вместе с тестом
  • Это напрямую связано с тем, что мы обсуждали в статье про тестовую среду: избегайте DDL в тестах и внимательно относитесь к автономным транзакциям.

    Явная очистка в teardown

    Идея: каждый тест удаляет за собой данные.

    Плюсы:

  • подходит, если тестируемая логика делает commit
  • можно очищать даже побочные эффекты автономных транзакций
  • Минусы:

  • надо дисциплинированно удалять в правильном порядке (с учётом внешних ключей)
  • больше кода и времени на прогон
  • Практика:

  • удаляйте по ключам тестовых данных
  • храните созданные ID в переменных теста, чтобы teardown был точным
  • Global Temporary Table как изоляция для промежуточных данных

    Global Temporary Table полезна, если тестам нужны промежуточные таблицы или staging, но нельзя допускать пересечений между сессиями.

    Создаётся один раз (DDL), а данные в ней живут на уровне сессии или транзакции.

    Документация по синтаксису: Oracle Database SQL Language Reference: CREATE TABLE

    Пример:

    Почему truncate почти всегда плох для тестов

    truncate table — это DDL, а значит:

  • он делает неявные commit
  • может влиять на другие тесты и пользователей
  • часто требует широких прав
  • Если вы не управляете полностью контуром и не запускаете тесты строго последовательно в отдельной базе, truncate обычно ухудшает ситуацию.

    Практические правила устойчивых тестовых данных

  • Делайте тесты самодостаточными: каждый тест сам создаёт то, что ему нужно.
  • Держите фикстуры минимальными: меньше строк, меньше колонок, меньше зависимостей.
  • Выбирайте одну стратегию очистки для проекта и соблюдайте её.
  • Если нужен параллельный прогон, избегайте фиксированных ключей без изоляции.
  • Не используйте прод-данные без маскирования и согласования с политикой безопасности.
  • Не проверяйте «точные ID», если вы генерируете уникальные ключи; проверяйте свойства и содержимое записей.
  • Итоги

  • Фикстуры — это управляемое состояние данных для тестов; их задача — исключить зависимость от «того, что уже лежит в базе».
  • Генерация данных должна быть детерминированной; случайность допустима только при контролируемом seed и ограниченных диапазонах.
  • Маскирование нужно, когда тесты используют реалистичные данные; лучше всего работать на синтетических данных, а при необходимости маскировать согласованно и необратимо.
  • Очистка после тестов — обязательна: через rollback, teardown или сочетание подходов, с учётом DDL и автономных транзакций.
  • 6. Покрытие, качество и диагностика: отчёты, профилирование, отладка

    Покрытие, качество и диагностика: отчёты, профилирование, отладка

    Unit-тестирование в Oracle ценится за быструю обратную связь и контроль регрессий. Но на практике команда упирается в три вопроса:

  • как увидеть результаты так, чтобы они были полезны разработчику и CI
  • как понять, что тесты проверяют достаточно (не только что они зелёные)
  • что делать, когда тест падает или становится нестабильным
  • В предыдущих статьях курса мы построили фундамент:

  • определили, что такое unit-тест в PL/SQL и как выбирать границы (unit против интеграции)
  • настроили среду: схемы, права, изоляция, транзакции, NLS и контекст
  • выбрали инструменты: utPLSQL, SQL Developer, CLI/SQLcl
  • обсудили проектирование тестируемого кода: зависимости, стабы, шпионы
  • разобрали тестовые данные: фикстуры, генерация, маскирование, очистка
  • Теперь соберём слой контроля качества и диагностики: отчёты, покрытие, профилирование и приёмы отладки.

    Полезные источники:

  • utPLSQL Documentation
  • utPLSQL CLI
  • Oracle Database PL/SQL Packages and Types Reference
  • DBMS_PROFILER (Oracle documentation)
  • DBMS_HPROF (Oracle documentation)
  • DBMS_UTILITY (Oracle documentation)
  • !Как результаты прогона превращаются в отчёты и артефакты

    Отчёты: как сделать результаты тестов полезными

    Отчёт о тестах нужен двум аудиториям:

  • разработчику локально, чтобы быстро понять, что сломалось
  • CI, чтобы зафиксировать статус, сохранить артефакты и показать историю
  • Что важно в отчёте

    Хороший отчёт отвечает на вопросы:

  • какой набор тестов запускался
  • какие тесты упали и по какой причине
  • где в коде ошибка (если это исключение)
  • насколько стабильна ситуация во времени (тренд)
  • Практически это упирается в два аспекта:

  • структура тестов и именование
  • формат репортинга
  • Именование и структура, которые ускоряют диагностику

    Старайтесь, чтобы по одному названию было ясно поведение и условие:

  • тест описывает ожидаемый результат: например, «Выбрасывает ошибку, если статус закрыт»
  • suite группирует тесты по модулю: например, «Orders API», «Pricing Rules»
  • Если тесты названы по внутренним деталям реализации, отчёт перестаёт быть исполняемой спецификацией и хуже переживает рефакторинг.

    Форматы репортинга: локально и в CI

    На практике чаще всего используют:

  • читаемый консольный вывод для локального запуска
  • машиночитаемый формат для CI, обычно в стиле xUnit/JUnit XML
  • utPLSQL поддерживает разные репортёры и сценарии запуска, а утилита utPLSQL CLI упрощает запуск из командной строки и сохранение отчётов в файлы.

    Рекомендации для CI:

  • сохраняйте отчёт как артефакт сборки
  • делайте отчёт доступным по ссылке из пайплайна
  • храните историю прогонов, чтобы видеть деградации и флейки
  • Покрытие кода: как измерять и как не обманываться

    Что такое покрытие

    Покрытие кода показывает, какие участки PL/SQL были выполнены при запуске тестов. Это помогает:

  • находить «слепые зоны», где тестов нет
  • контролировать, что важная логика действительно исполняется в тестах
  • безопаснее рефакторить: видно, что тесты затрагивают модуль
  • utPLSQL умеет собирать покрытие и формировать отчёты покрытия, детали зависят от версии и конфигурации, поэтому ориентируйтесь на раздел Code coverage в utPLSQL Documentation.

    Что покрытие не гарантирует

    Покрытие отвечает на вопрос «исполнялось ли», но не отвечает на вопрос «проверялось ли правильно». Типовые ловушки:

  • строка исполнилась, но ассёрта нет, и ошибка не ловится
  • тест проходит без проверок, потому что в нём нет значимых ожиданий
  • покрытие высокое, но проверяются только «счастливые пути», а ошибки и границы пропущены
  • Практическое правило: покрытие полезно как индикатор, но качество тестов определяется смыслом проверок.

    Какие виды покрытия вам реально нужны

    Наиболее практичные варианты интерпретации:

  • покрытие ключевых пакетов и критичной логики
  • покрытие ветвлений и обработчиков ошибок (там, где бизнес-риски)
  • Не пытайтесь сразу довести всё до «идеальных процентов». Лучше договориться о поэтапной цели:

  • зафиксировать текущее покрытие и сделать его видимым
  • поднять покрытие на критичных модулях
  • не допускать падения покрытия при изменениях
  • Порог покрытия в CI: как ставить реалистично

    Порог покрытия в CI нужен как защита от деградации, но он должен быть практичным:

  • начните с порога на изменяемые модули или на новый код
  • используйте порог как сигнал для обсуждения, а не как способ блокировать всё
  • учитывайте, что часть кода может быть трудно покрыть unit-тестами из-за интеграций и побочных эффектов
  • Если вы видите, что покрытие сложно поднять, часто это симптом архитектуры: слишком много неявных зависимостей, прямой доступ к таблицам, время и контекст внутри доменной логики. Это связывается с темой из статьи про проектирование тестируемого PL/SQL.

    Качество тестов: что контролировать помимо покрытия

    Ниже набор практичных критериев качества, которые хорошо работают именно в Oracle-проектах.

    Детерминизм и изоляция

    Проверяйте, что тесты:

  • не зависят от sysdate и среды без контроля
  • не зависят от «данных, которые уже есть»
  • не оставляют следов (rollback или teardown)
  • Если тест «иногда падает», это почти всегда один из факторов из статьи про среду: транзакции, автономные транзакции, NLS, параллельность, общие ключи.

    Сила ассёртов

    Слабые проверки создают иллюзию качества. Примеры слабых проверок:

  • «не упало» вместо проверки результата
  • to_be_not_null там, где можно проверить точные атрибуты
  • Практичный баланс:

  • проверяйте наиболее важные свойства результата
  • не проверяйте лишние детали реализации, которые часто меняются
  • Отдельные тесты на ошибки и границы

    Для бизнес-логики в PL/SQL чаще всего важны:

  • граничные значения (0, null, максимум, минимум)
  • некорректные статусы и запретные переходы
  • отсутствие обязательных параметров
  • Выделяйте это в отдельные тесты, чтобы отчёт сразу показывал, какая часть контракта нарушена.

    Диагностика падений: как быстро понять причину

    Минимизируйте «площадь поиска»

    Если упал тест, цель не «проверить всё», а максимально быстро локализовать:

  • какой тест упал
  • на каких данных
  • в каком месте кода
  • Практика:

  • запускайте один suite или один пакет тестов при отладке
  • делайте Arrange минимальным, чтобы легче воспроизвести
  • не переиспользуйте слишком сложные общие фикстуры, если они скрывают причину
  • Делайте сообщения ошибок диагностичными

    Когда ассёрт падает, сообщение должно помогать:

  • что ожидали
  • что получили
  • при каких входных данных
  • Если вы формируете собственные сообщения или логируете дополнительную диагностику, следите, чтобы она не загрязняла среду и не требовала автономных транзакций.

    Стек ошибки Oracle: как его извлекать и показывать

    При ошибках в PL/SQL важно видеть стек и backtrace. Для этого полезны функции из DBMS_UTILITY, например форматирование стека и backtrace, описание смотрите в DBMS_UTILITY (Oracle documentation).

    Пример вспомогательной обёртки для диагностики в тестах:

    Как применять:

  • в обработчике исключения внутри теста добавляйте app_test.diag.error_details в сообщение падения
  • это помогает быстро понять точку в коде, где возникла ошибка
  • Работа с DBMS_OUTPUT как с временной мерой

    DBMS_OUTPUT удобен как временный инструмент при отладке, но как постоянная диагностика он слаб:

  • вывод легко потерять в CI
  • он плохо структурирован
  • он не заменяет ассёрты
  • Если используете DBMS_OUTPUT, фиксируйте правило:

  • после починки теста удаляйте шумный вывод или оставляйте только критичный минимум
  • Профилирование: когда тесты проходят, но всё медленно

    Профилирование отвечает на другой вопрос, чем покрытие:

  • покрытие говорит «что исполнялось»
  • профилирование говорит «где потратили время»
  • Это важно, когда:

  • тесты стали выполняться долго
  • пакет работает корректно, но есть жалобы на производительность
  • вы хотите убедиться, что оптимизация действительно улучшила ситуацию
  • DBMS_PROFILER

    DBMS_PROFILER собирает статистику выполнения PL/SQL по строкам и единицам кода. Документация: DBMS_PROFILER (Oracle documentation).

    Типовой подход:

  • включить профилирование
  • выполнить интересующий сценарий (например, вызов API или запуск набора тестов)
  • выключить профилирование
  • проанализировать результаты в таблицах профайлера
  • Схематичный пример:

    Важно:

  • для DBMS_PROFILER нужны таблицы-репозитории профайлера и права на них
  • профилирование замедляет выполнение, поэтому используйте его точечно
  • DBMS_HPROF

    DBMS_HPROF собирает иерархический профиль вызовов: кто кого вызвал и сколько времени ушло в каждом узле. Документация: DBMS_HPROF (Oracle documentation).

    Минимальный сценарий:

  • запустить трассировку HPROF
  • выполнить сценарий
  • остановить трассировку
  • получить отчёт из trace-файла
  • DBMS_HPROF особенно полезен, когда нужно понять, какой слой «съедает» время:

  • бизнес-логика
  • репозитории и запросы
  • вспомогательные зависимости
  • Практический совет: профилируйте не «всё подряд», а один воспроизводимый сценарий, который можно запускать много раз с одинаковыми входными данными.

    Отладка нестабильных тестов: типовые причины и решения

    Нестабильность почти всегда связана с нарушением принципов из предыдущих статей. Самые частые причины:

  • зависимость от текущего времени и часового пояса
  • случайные данные без фиксированного seed
  • общие ключи и конфликты при параллельном запуске
  • пакетные переменные и несброшенное глобальное состояние
  • автономные транзакции, которые оставляют следы
  • неявные commit из-за DDL
  • Стратегия лечения флейков:

  • добиться воспроизводимости локально, запуская один проблемный тест много раз
  • убрать неявные зависимости: время, контекст, NLS
  • сделать данные уникальными или изолированными
  • гарантировать очистку в aftereach даже при падении
  • Практический чеклист для команды

  • Отчёты доступны локально и в CI, результаты сохраняются как артефакты.
  • Имена suite и test отражают поведение, а не детали реализации.
  • Покрытие видно и используется для поиска «дыр», но не подменяет качество ассёртов.
  • Есть отдельные тесты на ошибки и граничные случаи.
  • При падении теста вы умеете быстро получить backtrace и контекст ошибки.
  • Профилирование применяется точечно для медленных сценариев через DBMS_PROFILER или DBMS_HPROF.
  • Нестабильность тестов лечится устранением зависимостей и улучшением изоляции, а не «повторным прогоном до зелёного».
  • Итоги

  • Отчёты делают тесты полезными: локально для быстрой починки, в CI для истории и контроля.
  • Покрытие помогает находить слепые зоны, но не гарантирует качество проверок.
  • Качество тестов определяется детерминизмом, изоляцией, силой ассёртов и покрытием границ и ошибок.
  • Для диагностики падений в Oracle критичны стек ошибки и backtrace, их удобно получать через DBMS_UTILITY.
  • Профилирование (DBMS_PROFILER, DBMS_HPROF) решает задачу производительности и дополняет тестирование, а не заменяет его.
  • 7. CI/CD для Oracle: автоматический запуск тестов и контроль релизов

    CI/CD для Oracle: автоматический запуск тестов и контроль релизов

    CI/CD в контексте Oracle — это практика, при которой изменения в схеме и PL/SQL-коде автоматически собираются, разворачиваются в контролируемой среде, проверяются тестами (utPLSQL) и только после этого допускаются к релизу.

    Эта статья связывает воедино темы курса:

  • из основ unit-тестирования мы берём цель: быстрые, детерминированные проверки поведения
  • из подготовки среды — раздельные схемы, минимальные права, транзакционную изоляцию и контроль NLS/контекста
  • из инструментов — utPLSQL, репортёры, CLI/SQLcl и форматы отчётов
  • из проектирования тестируемого PL/SQL — управление зависимостями, чтобы тесты могли быть настоящими unit-тестами
  • из работы с данными — фикстуры, предсказуемая генерация, очистка
  • из покрытия и диагностики — отчёты, JUnit XML для CI, сбор покрытия и практики отладки
  • Полезные источники:

  • utPLSQL
  • utPLSQL CLI
  • Oracle SQLcl
  • Liquibase
  • Flyway
  • Jenkins
  • GitLab CI/CD
  • GitHub Actions
  • Термины, которые нужны для CI/CD

  • CI (Continuous Integration) — автоматическая проверка каждого изменения: сборка, миграции, тесты, отчёты.
  • CD (Continuous Delivery/Deployment) — автоматическая доставка проверенного изменения в окружение (например, staging), а иногда и в production.
  • Пайплайн — последовательность шагов, которые выполняет CI-система.
  • Quality gate — правило, которое блокирует дальнейшее продвижение изменений, если условия не выполнены (например, тесты не зелёные).
  • Артефакты — файлы, сохраняемые после пайплайна: JUnit XML, отчёты покрытия, логи.
  • Целевая архитектура пайплайна для Oracle

    Задача пайплайна — сделать прогон тестов воспроизводимым. Минимальный практичный скелет обычно такой:

  • Получить исходники (DDL, PL/SQL, тесты).
  • Поднять или подготовить БД для прогона.
  • Накатить миграции схемы.
  • Установить или обновить тесты.
  • Запустить utPLSQL.
  • Сохранить отчёты и применить quality gate.
  • !Блок-схема этапов пайплайна и артефактов

    Где живут тесты и как они попадают в CI

    Есть два распространённых подхода, и выбор влияет на безопасность и повторяемость.

    Тесты как часть репозитория (рекомендуемый базовый вариант)

  • тестовые пакеты utPLSQL хранятся рядом с кодом приложения
  • пайплайн разворачивает тесты в тестовую схему (например, APP_TEST)
  • Плюсы:

  • версия тестов всегда согласована с версией кода
  • изменения тестов проходят code review
  • Тесты как отдельный репозиторий

    Используют, если тестами управляет отдельная команда или требуется отдельный жизненный цикл.

    Минусы:

  • выше риск рассинхронизации версий тестов и кода
  • Практическая рекомендация курса: держите тесты рядом с кодом и разворачивайте их миграциями или скриптами так же, как и основной PL/SQL.

    Подготовка базы для прогона: постоянная или временная

    Решение определяет скорость, стоимость и стабильность.

    Постоянная тестовая БД (shared environment)

    Пайплайн использует заранее существующую БД (например, CI_DB).

    Плюсы:

  • проще подключиться
  • не нужно поднимать БД на каждый запуск
  • Минусы:

  • больше рисков конфликтов (параллельные прогоны, «мусор» от падений)
  • сильнее требования к изоляции данных и уникальности ключей
  • Временная БД на каждый прогон (ephemeral environment)

    Пайплайн поднимает БД (часто в контейнере) и уничтожает после прогона.

    Плюсы:

  • максимальная воспроизводимость
  • параллельность проще
  • Минусы:

  • сложнее инфраструктурно
  • дольше старт, если БД тяжёлая
  • Если вы рассматриваете контейнеризацию Oracle для CI-окружений, ориентируйтесь на официальные Docker-файлы Oracle:

  • Oracle Database Docker Images
  • Миграции схемы: обязательный слой перед тестами

    Если схема не приводится к ожидаемому состоянию, тесты теряют смысл: вы тестируете не то, что собираетесь релизить.

    В пайплайне обычно выделяют шаг migrate:

  • накатываются таблицы, типы, пакеты приложения
  • создаются/обновляются тестовые пакеты
  • создаются вспомогательные объекты тестов (например, test_data пакеты, GTT)
  • Для этого часто используют:

  • Liquibase
  • Flyway
  • Ключевой принцип: одинаковый механизм доставки кода в CI и в релиз, иначе вы тестируете одно, а выкатываете другое.

    Автоматический запуск utPLSQL в CI

    Есть два практичных способа: через utPLSQL CLI или через SQLcl/SQL*Plus со скриптом, который вызывает ut.run.

    Вариант с utPLSQL CLI

    utPLSQL CLI удобен тем, что умеет работать с репортёрами и писать результаты в файлы, включая JUnit XML.

    Источник:

  • utPLSQL CLI
  • Типовая идея команды (опции зависят от версии CLI и ваших требований):

    Что важно концептуально:

  • подключение идёт под тестовым пользователем
  • результаты сохраняются в машиночитаемых форматах
  • CI публикует файлы как артефакты
  • Вариант со скриптом и SQLcl

    SQLcl удобен как универсальный раннер: вы вызываете ut.run и выводите результат.

    Источник:

  • Oracle SQLcl
  • Пример минимального скрипта run_tests.sql:

    Запуск в CI:

    Практическое ограничение: если вам нужен JUnit XML и стандартизованная публикация отчётов, CLI часто удобнее, чем «чистый вывод».

    Отчёты и артефакты: что сохранять

    Минимальный набор, который делает CI полезным:

  • JUnit/xUnit XML отчёт о тестах (для UI CI-системы)
  • текстовый лог прогона (для быстрой диагностики)
  • Расширенный набор:

  • отчёт покрытия (если вы собираете coverage)
  • дамп диагностической информации при падении (например, форматированный backtrace, если вы добавляете его в сообщения)
  • Из статьи про диагностику напоминание: отчёт должен помогать ответить на вопросы какой тест, почему упал, где в коде упал.

    Quality gates: правила, которые реально работают

    Quality gate должен быть простым, измеримым и связанным с риском.

    Типовые гейты для Oracle-модуля с utPLSQL:

  • пайплайн падает, если есть упавшие тесты
  • пайплайн падает, если тесты не запустились (ошибка компиляции, нет соединения, нет прав)
  • опционально: минимальный порог покрытия для критичных пакетов
  • Важно: порог покрытия не должен превращаться в «игру в проценты». Его роль — не допускать деградации и подсвечивать слепые зоны.

    Контроль релизов: как связать тесты и продвижение в окружения

    Разделяйте этапы доставки

    Практичная модель окружений:

  • CI (быстрые проверки на каждый коммит)
  • staging (проверка релизного кандидата ближе к боевым условиям)
  • production
  • Тесты utPLSQL чаще всего запускают:

  • обязательно в CI
  • часто в staging
  • выборочно в production (зависит от политики и времени простоя)
  • Версионирование изменений схемы

    Чтобы контролировать релизы, вам нужна видимая версия состояния схемы:

  • таблица истории миграций (Liquibase/Flyway делают это автоматически)
  • правила: «что считается применённым релизом» (например, тег в Git + применённый набор миграций)
  • Тогда вопрос «какой код сейчас в базе» перестаёт быть гаданием.

    Стратегии отката

    В Oracle откат схемы может быть сложным, поэтому в релизной дисциплине важны два принципа:

  • миграции должны быть обратимыми или компенсируемыми, где это возможно
  • изменения делайте совместимыми по этапам, особенно если есть зависимые приложения
  • Если команда использует Edition-Based Redefinition, это отдельный продвинутый слой управления релизами. В рамках этой статьи достаточно помнить: любые механизмы безопасного релиза выигрывают от того, что тесты запускаются автоматически на каждом шаге.

    Секреты, права и безопасность в CI

    CI/CD для БД почти всегда ломается либо из-за прав, либо из-за секретов.

    Практичные правила:

  • храните пароли и connect-string в секрет-хранилищах CI (а не в репозитории)
  • используйте отдельного пользователя для тестов (например, APP_TEST) с минимальными правами
  • выдавайте тестам доступ через execute на публичный API, а не прямой доступ ко всем таблицам
  • учитывайте definer rights и invoker rights (из статьи про среду): при authid current_user тестовой схеме понадобятся дополнительные объектные права
  • Как связать тестовые данные и CI

    В CI чаще всего вы хотите, чтобы прогон был:

  • параллельным
  • повторяемым
  • без ручной очистки
  • Поэтому правила из статьи про тестовые данные становятся практикой пайплайна:

  • избегайте DDL внутри тестов, иначе поймаете неявные commit
  • используйте транзакционный откат, где это возможно
  • для тестов, которые проверяют commit-поведение или автономные транзакции, используйте явный teardown
  • делайте уникальные ключи для параллельности (например, через тестовую последовательность)
  • Типовые причины падений пайплайна и быстрые проверки

  • Не компилируется пакет или тест: проверьте шаг миграций и права на create procedure в тестовой схеме.
  • Тесты не видят объекты приложения: проверьте grant execute на нужные пакеты и режим authid.
  • Флейки только в CI: проверьте NLS/таймзону сессии и общие ключи данных (параллельность).
  • Тесты проходят локально, а в CI нет: почти всегда проблема в различии версии схемы или окружения, поэтому миграции должны быть обязательным шагом.
  • Мини-чеклист: готовность utPLSQL к CI/CD

  • Тесты лежат в репозитории и устанавливаются так же, как код (скриптами или миграциями).
  • Есть отдельная тестовая схема с минимальными правами.
  • Пайплайн поднимает схему до нужной версии перед запуском тестов.
  • Тесты запускаются автоматизированно (utPLSQL CLI или SQLcl).
  • Отчёты сохраняются как артефакты, CI показывает результат в интерфейсе.
  • Есть хотя бы один quality gate: «нет упавших тестов».
  • Итоги

  • CI/CD для Oracle строится вокруг воспроизводимости: миграции схемы + автоматический запуск utPLSQL.
  • utPLSQL CLI и SQLcl решают задачу безынтерактивного прогона, а JUnit XML превращает результаты в понятный CI-отчёт.
  • Quality gates защищают релиз: тесты должны быть зелёными, а покрытие можно использовать как индикатор слепых зон.
  • Безопасность обеспечивается раздельными схемами, минимальными правами и корректным управлением секретами.