Привет, Хабр!

Меня зовут Игорь Левин. Я разработчик 1С в Sportmaster Lab. Наша команда работает над проектом Shipdocs 2.0 — это продукт, который состоит из двух информационных систем. Он обеспечивает информационную поддержку бизнес-области закупок и цепей поставок. Часто мы автоматизируем кроссфункциональные бизнес-процессы на стыке с международной логистикой и финансовым управлением.

Вот ключевые функции Shipdocs 2.0:

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

  • согласование документов внутри подразделений компаний СМ,

  • проверка и согласование заявок на перевозку (букирование перевозок у экспедитора),

  • различная оперативная отчетность.

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

Наша команда состоит из двух аналитиков, двух тестировщиков, двух с половиной программистов и лидер продукта.

Управление информационных сервисов (УИС) «Спортмастер» насчитывает 1,5 тысячи сотрудников, которые поддерживают около 200 информационных систем. В управление входит департамент QA. Центр компетенции департамента QA выделяет пять типов автотестов: 

  • юнит-тесты

  • интеграционные тесты

  • скрин тесты

  • end-to-end тесты

  • Health-тесты

Скажем пару слов о каждом из выделенных типов тестирования:

Юнит тестирование - процесс в программировании, позволяющий проверить на корректность отдельные классы/методы/функции исходного кода программы, наборы из одного или более программных классов/методов/функций вместе с соответствующими управляющими данными, процедурами использования и обработки. Все внешние вызовы имитируются. Обычно выполняется разработчиками. 

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

Интеграционное тестирование разделяется на следующие виды: 

  • Компонентные тесты

  • API-тесты

  • Тесты внешних связей 

Screen-тестирование (Layout-тестирование) — автоматизированное визуальное тестирование элементов пользовательского интерфейса. 

Сквозное тестирование (end2end-тестирование) — тестирование системы в целом с эмуляцией реальной пользовательской среды. Сквозным оно называется, потому что проверяют бизнес-функции системы, при этом развернуто все приложение(ия), без заглушек. То есть, мы тестируем, что с точки зрения конечного пользователя система работает так, как планировалось.

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

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

Выбор пути

После осознания того, что мы хотим тестировать, перед нами встал классический вопрос: To be, or not to be? реализовать свое решение или взять уже имеющееся на рынке? 

Очевидные плюсы готового продукта — не нужна разработка, есть обширный функционал. Из минусов — нужно разбираться с этой функциональностью, кастомизировать, не исключая шанс, что на все 100% настроить его под себя не получится. Есть риск, что его перестанут поддерживать. Кроме того, часто функционал обширен, а тебе нужно всего 10% от него. 

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

Честно, мы пробовали оба варианта. Еще до моего прихода в «Спортмастер» команда сделала несколько подходов к имеющимся на рынке решениям, но все они оказались неудачными (не продукты, а попытки). Поэтому выиграла внутренняя разработка. Работа закипела.

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

  • подсистема в рамках основной конфигурации, 

  • набор внешних обработок,

  • расширение.

К минусам отдельной подсистемы в рамках основной конфигурации можно отнести тот факт, что есть риск по ошибке пронести код автотестов в рабочую среду. Нужна обвязка тестируемых процедур и функций. Кроме того, все тестируемые процедуры и функции должны быть экспортными или писать заглушки с кучей case-ов.

Если рассматривать внешние обработки, то здесь те же самые обвязки, тот же экспорт, но к ним еще добавляется проблема хранения истории изменения наборов обработок. Можно, конечно, Git подключить, но зачем, если можно этого не делать. Или сделать, но на более поздних этапах для code-review и SonarQube. 

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

Идеальным мы сочли вариант с расширениями. Расширения хранятся отдельно, соответственно, пронести по ошибке уже не получится. Они поддерживают механизм хранилища.

Можно относиться к хранилищу 1С, как угодно, но все-таки это хороший стабильный функционал, которым можно пользоваться для групповой разработки и хранения истории. И один из самых важных пунктов — есть аннотации «Вместо» и «После». «Вместо» мы используем для интеграционных тестов, «После» — для юнит-тестов. И тут нам уже не нужен никакой экспорт. 

Тестовый и рабочий контуры

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

Разработчик на своей базе пишет код, тестирует его, там же может запустить автотесты. Завершив отладку и предварительное тестирование, он кладет основной код в хранилище разработки, а код автотестов — в хранилище расширения автотестов. Далее при передаче кода в code-review происходит автопронос его на тестовую БД. Тестировщик, осуществляющий ручное тестирование, проводит тестирование на тестовой БД. 

Кроме того, на тестовом контуре есть отдельная конфигурация для запуска автотестов раз в день. И все в ней обновляется в автоматическом режиме. Также прикручен SonarCube, который выполняет статический анализ нашего кода.

Вот как выглядит рабочий контур:

Разница с предыдущей в том, что из хранилища разработки посредством рабочей базы мы руками переносим в рабочее хранилище код, который необходимо накатить на рабочую базу, но который пока не обновили через F7. Запускаются автотесты. После проверки доступных структур, если все ОК, можно обновлять конфигурацию базы данных. 

Описание механизма

Это основная обработка по запуску автотестов. Из интересного здесь — дерево тестов. На верхнем уровне тип теста — интеграционный или юнит. Уровнем ниже следуют типы объектов: справочники, документы и регистры. А на последнем уровне находятся сами имена тестов. 

Поскольку мы начинали автоматизацию с интеграционных тестов, уместным показалось хранить эти тесты пообъектно. 

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

Сначала строится дерево автотестов, далее мы обегаем его, и перед запуском конкретного теста получаем его входные параметры. И начинаем транзакцию. 

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

Перейдем к составным частям расширения.

Основные части общего расширения — это обработка по запуску, обработок с автотестами, общие модули для служебных функций и процедур, подсистема для отображения и справочник для формирования наборов данных в предприятии. А вот в расширении конкретной конфигурации хранятся сами обработки с автотестами, макеты с тестовыми и эталонными данными, плюс модули тестируемых объектов. В основном это модули менеджеров, но вообще это могут быть любые модули. Разделение расширение на 2 части вызвано архитектурными тенденциями. Мы стараемся не делать монолитов (получается не всегда), а выделять функциональную область в отдельную конфигурацию на базе единой библиотеки (аналог БСП, просто постарше). Аналогичный подход решили сразу применить к расширению для тестирования. Общая часть - универсальная и единая с общим репозиторием, коллективной разработкой и одним ответственным. Плюс уникальные части для каждой конфигурации, которые используют общую часть.

Вот пример копии модуля менеджера, который хранится в расширении любого типичного справочника или документа. 

  1. ВернутьСписокАвтотестов() – возвращает список автотестов текущего объекта

  2. ВернутьНастройкиТеста() – возвращает параметры текущего автотеста

  3. ЮТ_ПолучитьДанныеОракля() – перехватывает обращение к Oracle и подменяет данные своими из макета, при необходимости сверяет структуры

  4. ЮТ_СозданиеИзменениеПрошлоКорректно() – проверяет корректность записи данных в БД

Перейдем к самим тестам. 

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

Наши основные интеграции:

  • БД Источник ???? Наша ИБ (загрузка данных из Oracle)

  • Наша ИБ ???? БД приемник (выгрузка данных в Oracle)

  • soap, rest ???? Наша ИБ

  • Наша ИБ ???? soap, rest

Начали мы с тестирования интеграции: 

БД Источник ???? Наша ИБ (загрузка данных из Oracle)

Цели тестирования были следующие:

  • Тестирование собственного кода без привлечения второй стороны (среда разработки)

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

Теперь подробнее о достижении этих целей:

Тестирование загрузки из Oracle без соединения

Наш тест передает управление механизму загрузки. В момент, когда загрузка обращается к Oracle, расширение перехватывает управление и подменяет структуру, которую должен был вернуть Oracle, на ту, которая поднимается из макета. После чего возвращаемся в обработку по загрузке. Загрузка отрабатывает на поднятых данных из макета и возвращает в автотест информацию об успешной (или не очень) записи в базу. 

Если запись не удалась, тест падает, если все корректно — тестирование продолжается. Дальше сверяем загруженные в БД данные, считанные при помощи автоматически сгенерированного 1С-запроса  с эталонными данными, хранящимися в макете. Далее передаем по эстафете результат в тест и в обработку по запуску тестов. 

В коде это выглядит вот так:

Тест передает управление механизму загрузки:

Расширение перехватывает управление в момент вызова процедуры/функции получения данных из Oracle и формирует нужную структуру в базе данных из mxl-расширения:

Механизм загрузки отрабатывает на данных, сформированных расширением, возвращает результат в виде флага успех/провал + строку ошибок, если есть:

Тест в случае получения информации об успешной загрузке производит сравнение данных, записанных в БД с данными эталонного макета MXL:

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

Тестирование структуры загрузки

Тест создает соединение с Oracle в самом начале и передает его в механизм загрузки. Соответственно, механизм загрузки обращается к базе и получает из нее структуру. Сверяем эту структуру с эталонной и возвращаем результат в обработку по запуску.

Тест создает соединение с источником загрузки данных и передает управление механизму загрузки:

Механизм загрузки выполняет обращение к Oracle:

Расширение перехватывает управление в момент после вызова процедуры/функции получения данных из Oracle, формирует нужную структуру в базе данных из mxl-расширения. Сверяет структуру данных из источника и из расширения (количество колонок и их имена):

Функция проверки на соответствие структур:

Тест передает по эстафете результаты выполнения загрузки:


По мере развития нашей базы, загрузив все, что можно, и обработав это, мы стали генерить что-то свое. Теперь нам нужно было тестировать еще и выгрузку. То есть пришло время тестирования Наша ИБ ???? БД приемник (выгрузка данных в Oracle)

Цели тут оказались аналогичные:

  • Тестирование собственного кода без привлечения второй стороны (среда разработки) 

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

Тестирование выгрузки в Oracle

То, что необходимо выгрузить, мы собираем при помощи планов обмена, добавляем туда стандартными средствами 1С. Тест помещает в план обмена нужные объекты, ненужные оттуда вычищает и передает управление механизму выгрузки. Он генерирует пакеты для того, чтобы положить в Oracle, но в этот момент идет перехват расширением и происходит сверка сформированного к выгрузке пакета с эталонными данными. Результаты мы возвращаем через тест в обработку запуска тестов.

Тестирование структуры, выгружаемой в Oracle

Создаем соединение, передаем управление обработке по выгрузке, она же формирует пакеты. Кладем мы только одну строчку в транзакции Oracle, чтобы после проверки доступности структур не осталось никаких данных. Фиксируем результаты, отменяем транзакцию и передаем результат по эстафете. 

Юнит-тесты

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

Одним из таких тестов стал тест на формирование документа «Упаковочный лист». «Упаковочный лист» — это документ с тремя табличными частями. 

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

Что мы сделали:

Тест вызывает процедуру по формированию таблиц, предназначенную для формирования документа — трех табличных частей и одной шапки. Далее он поднимает собственные эталонные таблицы и попарно их сверяет. Если ничего не сбилось, округления и группировки не перепутались, строк не стало меньше/больше, значит, все отлично. Сверяем и передаем результат.

Как происходит запуск автотестов

Наши админы написали скрипт powershell, который:

  1. Обновляет основную конфигурацию из основного хранилища конфигурации;

  2. Обновляет расширение из хранилища расширения;

  3. Обновляет конфигурацию БД и помещает последнюю версию расширения в ИБ;

  4. Запускает «1С Предприятие» под определенным пользователем и обработку по запуску автотеста;

  5. Выполняет рассылку с результатами

Комментарии (1)


  1. capitannemo
    05.10.2021 19:23
    +1

    Почему не 1С:Сценарное тестирование ?