Интеграционное тестирование#

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

Для интеграций такие тесты проверяют полный путь сообщения: получение, постановку в очередь, обработку, изменение бизнес-объектов, формирование ответа и запись логов.

Интеграционные тесты применяются для проверки:

  • бизнес-объектов;

  • API-классов;

  • Pkg-методов;

  • выборок;

  • SQL-запросов;

  • транзакционных операций;

  • фоновых задач;

  • REST API;

  • обработчиков интеграционных сообщений;

  • чтения и записи файлов;

  • взаимодействия с внешними системами.

Для интеграционных контуров обычно проверяются:

  • Btk_ExtSystem — внешняя система;

  • Rpl_Circuit — контур интеграции;

  • Rpl_IntegrationCircuitExt — расширенные настройки контура, включая cProps;

  • Rpl_IntXmlInMsg — входящие сообщения импорта;

  • Rpl_IntXmlState — исходящие сообщения экспорта и ответные сообщения;

  • Rpl_IntInSession — сессия импорта;

  • Rpl_IntOutSession — сессия экспорта;

  • Rpl_RequestHandlerPkg — REST-обработчик входящих сообщений;

  • Rpl_RunIntegrationPkg — запуск интеграции;

  • Rpl_ProcessIncomingMessagePkg — обработка входящих сообщений;

  • Rpl_GenerateMessagePkg — генерация сообщений экспорта;

  • Rpl_SendWebRequestPkg — отправка сообщений по HTTP;

  • Rpl_PutRequestIntoFolderPkg — выгрузка сообщений в файловый каталог;

  • Rpl_Queue, Rpl_MasterQueue, Rpl_Worker — очереди, мастер-очереди и обработчики очередей.

Пример объектов тестирования для контура обмена справочником валют:

  • контур интеграции example_circuit;

  • внешняя система example_system;

  • входящее сообщение Rpl_IntXmlInMsg;

  • исходящее ответное сообщение Rpl_IntXmlState;

  • метод обработки сообщения processMessage;

  • метод запуска контура Rpl_RunIntegrationPkg().run;

  • REST-обработчик Rpl_RequestHandlerPkg/sendMessage;

  • логи импорта и экспорта;

  • очередь сообщений, если контур выполняется через Queue Walker.

Для тестирования используется отдельная тестовая среда:

  • тестовая БД PostgreSQL;

  • тестовый контур приложения;

  • тестовые настройки модулей;

  • тестовые пользователи, роли и профили;

  • тестовые внешние сервисы или мок-сервисы;

  • отдельные файловые хранилища;

  • отдельные очереди сообщений.

Для интеграционного контура отдельно настраиваются:

  • сценарий: импорт, экспорт или оба процесса;

  • параметры cProps;

  • тестовые методы обработки сообщений;

  • тестовые адреса внешних сервисов;

  • признак тестирования контура, если требуется повторная обработка сообщений;

  • отдельные очереди и мастер-очереди;

  • тестовые файловые каталоги или хранилища.

Предупреждение

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

Подготовка тестирования#

Перед созданием теста определите:

  • какие справочники нужны;

  • какие бизнес-объекты должны существовать до запуска;

  • какие данные создаются внутри теста;

  • какие данные удаляются или откатываются после теста;

  • какие значения считаются ожидаемым результатом.

Примечание

Создавайте данные внутри теста, если это возможно. Это снижает зависимость от состояния тестовой БД и упрощает повторный запуск.

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

  1. Создать или найти тестовую внешнюю систему.

  2. Создать или найти тестовый контур интеграции.

  3. Подготовить XML-сообщение с уникальным внешним идентификатором.

  4. Создать сообщение импорта Rpl_IntXmlInMsg.

  5. Запустить обработку контура.

  6. Проверить создание или обновление бизнес-объекта.

  7. Проверить создание ответного сообщения Rpl_IntXmlState.

  8. Проверить логи импорта.

  9. Откатить транзакцию или удалить созданные данные.

Пример входящего XML-сообщения:

<MessagePack>
  <ObjectClass>Cur_Currency</ObjectClass>
  <Circuit>example_circuit</Circuit>
  <Message>
    <MessageID>TEST-CURRENCY-001</MessageID>
    <MessageType>object</MessageType>
    <MessageOrder>1</MessageOrder>
    <CreateDate>2026-05-05T10:00:00</CreateDate>
    <SystemSource>TestSystem</SystemSource>
    <Data>
      <Object>
        <ID>TEST-USD-001</ID>
        <OKV>840</OKV>
        <CAPTION>Тестовый доллар США</CAPTION>
      </Object>
    </Data>
  </Message>
</MessagePack>

Создание и настройка#

Базовый класс#

Интеграционный тест обычно требует:

  • контекста приложения;

  • подключения к тестовой БД;

  • доступа к Api;

  • доступа к Pkg;

  • тестового пользователя или прав;

  • транзакции;

  • очистки данных после выполнения.

Точный базовый класс зависит от проекта. В проектной документации нужно указать класс или trait, который подготавливает окружение.

Пример условного базового класса:

abstract class IntegrationTestBase extends ApiTest {
  protected val testCircuitName = "ExampleCircuit"
  protected val testExternalSystem = "example_system"

  protected def rollbackTestData(): Unit = {
    session.rollback()
  }

  protected def runCircuit(): Unit = {
    Rpl_RunIntegrationPkg().run(testCircuitName)
  }
}

Структура тестового класса#

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

  1. Объявление тестового класса.

  2. Подключение нужных трейтов.

  3. Подготовка общих тестовых данных.

  4. Описание тестовых сценариев.

  5. Проверка результата.

  6. Очистка или откат данных.

Пример:

class CurrencyImportIntegrationTest extends IntegrationTestBase {
  test("импорт валюты создает объект и формирует ответное сообщение") {
    try {
      // подготовка данных
      val xml =
        <Object>
          <ID>TEST-USD-001</ID>
          <OKV>840</OKV>
          <CAPTION>Тестовый доллар США</CAPTION>
        </Object>

      val msg = Rpl_IntXmlInMsgApi().createMessage(
        testCircuitName.ns,
        xml.toString().ns
      )

      // выполнение операции
      val gid = ExampleCurrencyImportPkg().processMessage(msg)

      // проверка результата
      assert(gid.isNotNull, "После импорта должен вернуться GID объекта")

      // здесь проверяется созданный объект, ответное сообщение и лог импорта
    } finally {
      rollbackTestData()
    }
  }
}

Порядок создания теста#

  1. Определить сценарий.

  2. Определить компоненты сценария.

  3. Подготовить тестовые данные.

  4. Выполнить проверяемую операцию.

  5. Проверить результат в БД или через API.

  6. Проверить связанные изменения.

  7. Проверить ошибочные сценарии.

  8. Добавить очистку данных или откат транзакции.

  9. Запустить тест локально.

  10. Добавить тест в общий набор, если он стабилен.

Пример для импорта:

  1. Определить контур интеграции.

  2. Определить формат входящего XML.

  3. Подготовить тестовый объект во внешнем формате.

  4. Создать сообщение Rpl_IntXmlInMsg.

  5. Запустить обработчик сообщения или весь контур.

  6. Проверить созданный или измененный бизнес-объект.

  7. Проверить ответное сообщение Rpl_IntXmlState.

  8. Проверить лог импорта.

  9. Проверить повторную обработку того же сообщения.

  10. Добавить очистку тестовых данных.

Пример для экспорта:

  1. Создать или изменить бизнес-объект.

  2. Проверить, что изменение попало в журнал измененных объектов.

  3. Запустить агент формирования XML Snapshot.

  4. Проверить создание сообщения Rpl_IntXmlState.

  5. Запустить экспортный контур.

  6. Проверить отправку сообщения во внешний мок-сервис.

  7. Проверить лог экспорта.

  8. Проверить транспортную ошибку.

  9. Проверить повторную отправку, если сообщение не было доставлено.

Запуск тестов#

Интеграционные тесты запускаются:

  • из IDE;

  • через SBT;

  • в CI/CD;

  • вручную на тестовом стенде;

  • по расписанию.

Перед запуском проверьте:

  • доступность тестовой БД;

  • наличие миграций;

  • наличие тестовых справочников;

  • настройку внешних зависимостей или заглушек;

  • права тестового пользователя;

  • отсутствие обращений к промышленным сервисам.

Запуск всех тестов:

sbt test

Запуск конкретного тестового класса:

sbt "testOnly *CurrencyImportIntegrationTest"

Ручная проверка контура через REST:

curl -X POST \
  -H "Content-Type: application/xml" \
  --data @C:\test-data\message.xml \
  "http://localhost:8080/TESTDB/app/sys/rest/ss/pkg/Rpl_RequestHandlerPkg/sendMessageExampleCircuit?access_token=TEST_TOKEN"

Проверка результата#

Интеграционный тест считается успешным, если:

  • операция выполнена корректно;

  • данные записаны в ожидаемом виде;

  • связанные объекты созданы или изменены корректно;

  • транзакции обработаны корректно;

  • ошибочные сценарии завершаются ожидаемой ошибкой;

  • после теста не остается лишних данных;

  • повторный запуск дает тот же результат;

  • тест не зависит от порядка запуска других тестов.

Для интеграционных контуров дополнительно проверяется:

  • сообщение импорта создано в нужном контуре;

  • сообщение экспорта создано с правильным объектом и данными;

  • сессия импорта или экспорта завершилась в ожидаемом состоянии;

  • ошибки записаны в соответствующие логи;

  • ответное сообщение содержит корректный MessageID;

  • отрицательный ответ не создает дубль;

  • при NoPublish объект снимается с повторного экспорта;

  • при тестовом режиме контура сообщения сохраняются для повторной проверки.

Пример критериев для импорта:

  • создан один объект валюты;

  • внешний идентификатор сохранен;

  • повторная обработка обновляет объект, но не создает дубль;

  • сформировано ответное сообщение;

  • лог импорта не содержит ошибок;

  • после отката тест не оставляет данных.

Пример критериев для экспорта:

  • изменение бизнес-объекта подписало объект на экспорт;

  • создано сообщение Rpl_IntXmlState;

  • XML соответствует схеме выгрузки;

  • сообщение отправлено во внешний мок-сервис;

  • успешная отправка записана в лог экспорта;

  • при транспортной ошибке сообщение осталось в очереди на повторную отправку.

Отчетность#

Если тесты запускаются в CI/CD или перед релизом, фиксируйте:

  • дату и время запуска;

  • версию приложения;

  • версию БД;

  • тестовый стенд;

  • список выполненных тестов;

  • количество успешных и упавших тестов;

  • ошибки выполнения;

  • ссылки на логи.

Для интеграционных контуров дополнительно фиксируйте:

  • имя контура;

  • направление: импорт, экспорт или оба процесса;

  • идентификатор сессии импорта;

  • идентификатор сессии экспорта;

  • количество обработанных сообщений;

  • количество ошибок обработки данных;

  • количество критических ошибок;

  • последнее сообщение об ошибке импорта;

  • последнее сообщение об ошибке экспорта;

  • ссылку на монитор интеграции;

  • ссылку на логи CI/CD.

Шаблон отчета:

Поле

Значение

Дата запуска

2026-05-05 10:00

Версия приложения

указать версию

База данных

TESTDB

Контур

ExampleCircuit

Направление

import / export

Сессия импорта

указать ID

Сессия экспорта

указать ID

Выполнено тестов

указать количество

Успешно

указать количество

Ошибки

указать количество

Последняя ошибка импорта

указать текст ошибки

Последняя ошибка экспорта

указать текст ошибки

Ссылка на логи

указать ссылку

Особенности интеграционного тестирования#

Транзакции#

Проверяются:

  • успешное завершение транзакции;

  • откат при ошибке;

  • сохранение связанных объектов;

  • отсутствие частично записанных данных;

  • корректная обработка исключений;

  • отсутствие лишних коммитов внутри тестируемого кода.

Если интеграция выполняется через контур, например Rpl_RunIntegrationPkg().run("example_circuit"), запись в лог выполняется автоматически, в том числе при откате рабочей сессии.

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

Пример ручной фиксации ошибки в логе импорта:

val idvLog = Rpl_IntXmlImportApiPkg().newLogWithInMsg(
  idvIntInSession,
  ropIntXmlInMsg.get(_.id)
)

Rpl_IntImportLogApi().setsStackLT(
  idvLog,
  "Подробности ошибки обработки тестового сообщения"
)

Метод newLogWithInMsg создает лог импорта через Rpl_IntImportLogApi().newLogLT(), а setsStackLT записывает стек ошибки.

Пример ручной фиксации ошибки в логе экспорта:

Rpl_IntExportLogApi().saveLog(
  idpSession = ropOutMsg.get(_.idIntSession),
  gidpObj = ropOutMsg.get(_.gidObj),
  idpBoClass = ropOutMsg.get(_.gidObj).parseIdClass(),
  idpgObjExternal = ropOutMsg.get(_.gidObj).ns,
  spError = "Текст ошибки",
  bpError = true,
  sStack = "Стек ошибки",
  dpHandle = dpHandle,
  spAnswer = ropOutMsg.get(_.cAnswerBody),
  idInOutMsg = ropOutMsg.get(_.id)
)

Проверка бизнес-объектов#

Проверяются:

  • создание объекта;

  • значения по умолчанию;

  • обязательные атрибуты;

  • изменение состояния;

  • удаление объекта;

  • связанные объекты;

  • операции над объектом;

  • ограничения доступа.

Для интеграционного обмена дополнительно проверяются:

  • сопоставление объекта Global с внешним идентификатором;

  • поиск объекта по внешнему идентификатору;

  • создание объекта при отсутствии сопоставления;

  • обновление объекта при повторном сообщении;

  • запрет физического удаления интегрируемого объекта;

  • формирование ответного сообщения.

Пример сценария:

  • входящее сообщение содержит валюту с внешним идентификатором TEST-USD-001;

  • система ищет валюту по идентификатору внешней системы;

  • если объект не найден, создается новая валюта;

  • если объект найден, обновляются атрибуты;

  • после обработки формируется ответ OK;

  • повторная обработка сообщения не создает дубль.

Проверка API и Pkg-методов#

Проверяются:

  • входные параметры;

  • результат;

  • работа с БД;

  • ошибки;

  • вызов связанных API;

  • изменение состояния бизнес-объектов;

  • соблюдение бизнес-правил.

Для интеграционных контуров проверяются:

  • Rpl_RunIntegrationPkg().run;

  • Rpl_RunIntegrationPkg.runSynchroWithStaticParam;

  • Rpl_IntXmlInMsgApi().createMessage;

  • Rpl_IntXmlStateApi().register;

  • Rpl_RequestHandlerPkg;

  • методы из параметров контура:

    • sGetMessageForImport;

    • sProcessIncomingMessageMethod;

    • sGenerateMessageMethod;

    • sSendMessageMethod;

    • sAfterSendMethod;

    • sAnswerProcessMethod.

Пример синхронного запуска контура с переопределением метода получения импортных сообщений:

test("синхронный запуск контура возвращает результат без ошибок") {
  val params = Map(
    "sGetMessageForImport" -> "Bts_Procedure#HttpRequest.getImportMessageExample"
  )

  val result = Rpl_RunIntegrationPkg().runSynchroWithStaticParam(
    "ExampleImportSynchroCircuit",
    params
  )

  assert(
    !result.contains("errorCurrentImportSessionRpl"),
    s"Ошибка импортной сессии: ${result.get("errorCurrentImportSessionRpl")}"
  )

  assert(
    !result.contains("sLastErrorImportRpl"),
    s"Ошибка обработки объекта импорта: ${result.get("sLastErrorImportRpl")}"
  )
}

Пример обработки сообщения:

test("обработчик импортного сообщения создает валюту и ответное сообщение") {
  try {
    val xml =
      <Object>
        <ID>TEST-USD-001</ID>
        <OKV>840</OKV>
        <CAPTION>Тестовый доллар США</CAPTION>
      </Object>

    val msg = Rpl_IntXmlInMsgApi().createMessage(
      "example_circuit".ns,
      xml.toString().ns
    )

    val gid = ExampleCurrencyImportPkg().processMessage(msg)

    assert(gid.isNotNull, "После обработки сообщения должен вернуться GID созданного или обновленного объекта")

    // Дополнительно проверить объект, ответное сообщение и лог импорта
  } finally {
    session.rollback()
  }
}

Проверка выборок#

Проверяются:

  • SQL-запрос;

  • обязательные атрибуты;

  • фильтрация;

  • сортировка;

  • связи с бизнес-объектами;

  • права доступа;

  • мастер-деталь связи.

Для анализа обмена проверяются:

  • монитор интеграции;

  • сообщения импорта;

  • сообщения экспорта;

  • сессии импорта;

  • сессии экспорта;

  • логи импорта;

  • логи экспорта;

  • ошибки подписки на контур;

  • остановленные очереди.

Пример проверки сообщений импорта:

  1. Создать несколько тестовых сообщений.

  2. Одно сообщение оставить в очереди без сессии.

  3. Одно сообщение обработать в тестовой сессии.

  4. Выполнить запрос или открыть выборку сообщений импорта.

  5. Проверить разделение сообщений по состоянию.

  6. Проверить отдельное отображение очереди ожидающих сообщений.

Проверка интеграций#

Сценарии:

  • отправка REST-запроса во внешнюю систему;

  • прием REST-запроса от внешней системы;

  • обработка входящего сообщения;

  • публикация сообщения в очередь;

  • чтение сообщения из очереди;

  • загрузка файла из внешнего источника;

  • передача результата обработки во внешнюю систему.

Для внешних систем используйте тестовые контуры или мок-сервисы.

Пример входящего REST-сообщения:

curl -X POST \
  -H "Content-Type: application/xml" \
  --data @C:\test-data\currency-message.xml \
  "http://localhost:8080/TESTDB/app/sys/rest/ss/pkg/Rpl_RequestHandlerPkg/sendMessageExampleCircuit?access_token=TEST_TOKEN"

В примере:

  • TESTDB — тестовая БД;

  • sendMessageExampleCircuit — вызов обработчика sendMessage для контура ExampleCircuit;

  • TEST_TOKEN — токен тестового пользователя;

  • currency-message.xml — файл с тестовым XML-сообщением.

Пример сценария:

  1. Тест отправляет входящее сообщение в REST API.

  2. Rpl_RequestHandlerPkg создает сообщение импорта.

  3. Сообщение попадает в очередь контура.

  4. Запускается обработка контура.

  5. Система создает или обновляет бизнес-объект.

  6. Система записывает статус обработки.

  7. Система формирует ответное сообщение.

  8. Тест проверяет объект, статус и лог.

  9. Тест повторно отправляет сообщение и проверяет, что дубль не создан.

Проверка синхронной REST-интеграции#

Проверяются:

  • прием тела HTTP-запроса;

  • создание сообщения импорта из тела запроса;

  • установка idIntSession;

  • снятие сообщения с неподтвержденной подписи через setidCircuitUnassigned;

  • обработка сообщения в текущей импортной сессии;

  • формирование результата;

  • возврат ошибки при неуспешной обработке.

Метод создания импортных сообщений на основе тела HTTP-запроса указывается в параметре контура sGetMessageForImport.

def getImportMessage(ropCircuit: Rpl_CircuitApi#ApiRop): Unit = {
  val requestBody = Rpl_RunIntegrationPkg()
    .getExecutionParameters
    .get(Rpl_RequestHandlerPkg().sSynchroDataKey)

  requestBody match {
    case Some(value) =>
      val xml = XML.loadString(value)

      (xml \ "Object").filter(_.nonEmpty).foreach { node =>
        Rpl_IntXmlInMsgApi().createMessage(
          ropCircuit.get(_.sSystemName),
          node.toString().ns
        ) :/ { ropMessage =>
          Rpl_IntXmlInMsgApi().setidIntSession(
            ropMessage,
            Rpl_RunIntegrationPkg()
              .getExecutionParameters
              .get(Rpl_Pkg().sIdCurrentImportSessionRpl)
              .get
              .nl
          )

          Rpl_IntXmlInMsgApi().setidCircuitUnassigned(ropMessage, NLong())

          ropMessage
        }

        session.commit()
      }

    case _ =>
  }
}

Пример проверки синхронного импорта:

  1. Подготовить XML с одним или несколькими тегами Object.

  2. Выполнить POST-запрос на Rpl_RequestHandlerPkg/sendSynchro<НазваниеКонтура>.

  3. Проверить создание сообщений импорта.

  4. Проверить привязку сообщений к текущей сессии.

  5. Проверить создание или обновление бизнес-объекта.

  6. Проверить результат ответа.

  7. Проверить ошибки в результате выполнения.

Проверка файловых операций#

Проверяются:

  • загрузка файла;

  • скачивание файла;

  • сохранение метаданных;

  • связь файла с бизнес-объектом;

  • удаление файла;

  • ошибка недоступного хранилища;

  • версии файлов, если используется версионирование.

Для интеграционных контуров дополнительно проверяются:

  • чтение входящих файлов из каталога;

  • создание сообщений импорта на основе файлов;

  • настройка sFolderPath;

  • настройка sFileStorage;

  • выгрузка исходящих сообщений через Rpl_PutRequestIntoFolderPkg;

  • ошибка отсутствующего файла;

  • ошибка чтения или записи.

Пример:

  1. Подготовить тестовый XML-файл.

  2. Поместить файл в тестовый каталог из sFolderPath.

  3. Запустить метод получения сообщений для импорта.

  4. Проверить создание Rpl_IntXmlInMsg.

  5. Проверить содержимое сообщения.

  6. Запустить обработку.

  7. Проверить результат импорта.

  8. Удалить тестовый файл или откатить изменения.

Проверка фоновых заданий#

Проверяются:

  • запуск задания;

  • отбор данных;

  • изменение статусов;

  • обработка ошибок;

  • повторный запуск;

  • отсутствие повторной обработки;

  • логирование результата.

Для интеграций проверяются:

  • запуск контура через Rpl_RunIntegrationPkg().run("CircuitName");

  • задание периодического запуска контура;

  • агент XML Snapshot: отбор измененных объектов и формирование сообщений экспорта;

  • перенос сообщений из очереди в сессию;

  • Queue Walker;

  • обработка остановленных очередей.

Пример проверки экспорта:

  1. Создать или изменить тестовый бизнес-объект.

  2. Проверить попадание изменения в журнал измененных объектов.

  3. Запустить агент XML Snapshot.

  4. Проверить создание Rpl_IntXmlState.

  5. Запустить контур экспорта.

  6. Проверить отправку во внешний мок-сервис.

  7. Проверить лог сессии экспорта.

  8. Повторно запустить экспорт и проверить отсутствие повторной отправки, если контур не в тестовом режиме.

Пример запуска контура:

Rpl_RunIntegrationPkg().run("ExampleCircuit")

Проверка очередей#

Проверяются:

  • определение очереди для входящего сообщения;

  • заполнение Rpl_Queue;

  • привязка очереди к Rpl_MasterQueue;

  • назначение Rpl_Worker;

  • строгий порядок обработки;

  • параллельная обработка;

  • остановка очереди при ошибке;

  • возврат остановленной очереди на исполнение.

Пример строгой очереди:

  1. Создать три сообщения для одной очереди.

  2. Установить IsOnlyInOrder = true.

  3. Во втором сообщении подготовить ошибку.

  4. Запустить обработчик очередей.

  5. Проверить обработку первого сообщения.

  6. Проверить ошибку второго сообщения.

  7. Проверить, что третье сообщение не обработано.

  8. Проверить остановку очереди.

  9. Вернуть очередь на исполнение после исправления данных.

Пример параллельной очереди:

  1. Создать несколько независимых сообщений.

  2. Установить IsOnlyInOrder = false.

  3. Указать количество потоков через nParallelProcessIncomingMessageThreads или настройки приоритета мастер-очереди.

  4. Запустить обработку.

  5. Проверить независимую обработку сообщений.

  6. Проверить, что ошибка одного сообщения не блокирует всю очередь.

Проверка ошибок и исключений#

Проверяются:

  • некорректные входные данные;

  • отсутствие обязательных справочников;

  • нарушение бизнес-правил;

  • ошибка внешнего сервиса;

  • ошибка БД;

  • отсутствие прав доступа;

  • повторная обработка события;

  • недоступность файлового хранилища.

Для интеграционных контуров дополнительно проверяются:

  • ошибка формата XML;

  • ошибка поиска класса объекта;

  • ошибка сопоставления внешнего идентификатора;

  • отрицательный ответ от внешней системы;

  • транспортная ошибка;

  • лимит повторных выгрузок;

  • снятие объекта с экспорта через NoPublish;

  • запись ошибок в Rpl_IntImportLog;

  • запись ошибок в Rpl_IntExportLog;

  • критическая ошибка сессии.

Пример отрицательного ответа:

<MessagePack>
  <Response>
    <MessageID>TEST-MSG-001</MessageID>
    <ResponseID>TEST-RESP-001</ResponseID>
    <CreateDate>2026-05-05T10:01:00</CreateDate>
    <ObjectID>TEST-OBJECT-001</ObjectID>
    <Result>false</Result>
    <ResultCode>0</ResultCode>
    <Description>Документ не может быть перезаписан, проведен во внешней системе</Description>
    <NoPublish>true</NoPublish>
  </Response>
</MessagePack>

Пример ошибочного сценария:

  • сообщение не содержит обязательный внешний идентификатор;

  • объект не создается;

  • ошибка записывается в лог импорта;

  • формируется отрицательный ответ;

  • при NoPublish объект не подписывается на повторный экспорт.

Изоляция и повторяемость#

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

Для этого используются:

  • уникальные тестовые данные;

  • откат транзакции;

  • удаление временных данных;

  • независимость от порядка запуска тестов;

  • независимость от данных других тестов.

Уникальными должны быть:

  • MessageID;

  • внешний идентификатор объекта;

  • код тестового объекта;

  • имя тестового контура;

  • имя тестовой очереди;

  • имя тестового файла.

Пример очистки:

  • создавать данные с префиксом TEST_;

  • выполнять session.rollback() после теста;

  • удалять сообщения импорта и экспорта;

  • удалять тестовые файлы;

  • очищать тестовые очереди;

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

test("импорт сообщения создает объект и откатывает изменения после теста") {
  try {
    // подготовка тестового сообщения
    // запуск обработки
    // проверка результата
  } finally {
    session.rollback()
  }
}

Интеграция в массовый запуск или CI/CD#

В CI/CD можно запускать:

  • smoke-тесты после сборки;

  • тесты критичных бизнес-сценариев;

  • тесты миграций и обновлений;

  • тесты API-контрактов;

  • полный набор интеграционных тестов перед релизом или ночью.

Для интеграционных контуров:

Набор тестов

Когда запускать

Что проверяет

Smoke

После сборки

Доступность БД, запуск приложения, базовый запуск контура

Контрактные тесты

При изменении формата обмена

XML-структуру, обязательные теги, ответные сообщения

Интеграционные тесты контура

Перед релизом или ночью

Импорт, экспорт, очереди, логи, ошибки

Тесты миграций

Перед установкой обновления

Совместимость схемы БД и настроек интеграции

Регрессионные тесты

Перед выпуском версии

Критичные бизнес-сценарии обмена

Типовые проблемы#

Общие проблемы:

  • зависимость от состояния тестовой БД;

  • отсутствие очистки данных;

  • зависимость от порядка запуска тестов;

  • обращение к промышленным сервисам;

  • нестабильность внешних зависимостей;

  • слишком большой объем тестовых данных;

  • долгий запуск из-за инициализации контекста;

  • неявные коммиты внутри тестируемого кода;

  • разные результаты локально и в CI/CD;

  • непонятные сообщения об ошибках.

Проблемы интеграционных контуров:

  • неверный контур в REST-вызове;

  • не указан или некорректен токен доступа;

  • в URL не указана тестовая БД;

  • сообщение создано без привязки к нужному контуру;

  • сообщение синхронного импорта не привязано к текущей сессии через idIntSession;

  • сообщение не снято с неподтвержденной подписи через setidCircuitUnassigned;

  • не заполнен sProcessIncomingMessageMethod;

  • не заполнен sGenerateMessageMethod для экспорта;

  • мок-сервис возвращает нестабильные ответы;

  • при ручной фиксации ошибки используется обычная запись вместо LT-метода;

  • очередь остановилась при строгом порядке обработки;

  • тест ожидает повторную отправку, но контур не в тестовом режиме;

  • тест зависит от сообщения, уже обработанного другой сессией.

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

Рекомендуется:

  • проверять один бизнес-сценарий в одном тесте;

  • создавать тестовые данные внутри теста;

  • использовать уникальные коды и имена;

  • выполнять откат транзакции после теста;

  • не зависеть от порядка запуска;

  • не использовать промышленную БД и промышленные сервисы;

  • проверять успешные и ошибочные сценарии;

  • давать тестам понятные названия;

  • добавлять поясняющие сообщения в assert;

  • не перегружать тест лишними проверками.

Для интеграций дополнительно:

  • использовать отдельный тестовый контур;

  • включать bIsCircuitInTest, если нужна повторная проверка сообщений;

  • проверять состояние сообщений;

  • проверять логи сессий импорта и экспорта;

  • использовать мок-сервисы для HTTP-вызовов;

  • не использовать реальные промышленные токены;

  • проверять идемпотентность;

  • фиксировать ожидаемый MessageID;

  • проверять отрицательные ответы и повторные выгрузки;

  • проверять состояние очереди при ошибке.

Пример хорошего теста:

  • создает тестовое сообщение;

  • запускает обработку;

  • проверяет объект;

  • проверяет ответное сообщение;

  • проверяет лог;

  • откатывает данные;

  • запускается повторно без ручной подготовки.

Пример плохого теста:

  • зависит от конкретного объекта в тестовой БД;

  • отправляет запрос в промышленную систему;

  • не очищает сообщения из очереди;

  • не проверяет логи;

  • завершается успешно при ошибке обработки;

  • работает только после другого теста.

Ограничения#

Интеграционные тесты не проверяют:

  • производительность под высокой нагрузкой;

  • визуальное поведение пользовательского интерфейса;

  • все варианты сетевой нестабильности;

  • полное соответствие мок-сервиса реальной внешней системе.

Синхронные и асинхронные сценарии нужно проверять отдельно. Для промышленного запуска интеграционные тесты не заменяют мониторинг интеграции и анализ логов.