Автотесты на расширениях
Привет, Хабр!
Меня зовут Игорь Левин. Я разработчик 1С в Sportmaster Lab. Наша команда работает над проектом Shipdocs 2.0 — это продукт, который состоит из двух информационных систем. Он обеспечивает информационную поддержку бизнес-области закупок и цепей поставок. Часто мы автоматизируем кроссфункциональные бизнес-процессы на стыке с международной логистикой и финансовым управлением.
Вот ключевые функции Shipdocs 2.0:
автоматическое создание отгрузочных документов, необходимых для прохождения товаром таможни,
согласование документов внутри подразделений компаний СМ,
проверка и согласование заявок на перевозку (букирование перевозок у экспедитора),
различная оперативная отчетность.
Главные пользователи —менеджеры внешнеэкономической деятельности. И сегодня я хочу рассказать, как мы автоматизировали тестирование в рамках этого проекта.
Наша команда состоит из двух аналитиков, двух тестировщиков, двух с половиной программистов и лидер продукта.
Управление информационных сервисов (УИС) «Спортмастер» насчитывает 1,5 тысячи сотрудников, которые поддерживают около 200 информационных систем. В управление входит департамент QA. Центр компетенции департамента QA выделяет пять типов автотестов:
Скажем пару слов о каждом из выделенных типов тестирования:
Юнит тестирование — процесс в программировании, позволяющий проверить на корректность отдельные классы/методы/функции исходного кода программы, наборы из одного или более программных классов/методов/функций вместе с соответствующими управляющими данными, процедурами использования и обработки. Все внешние вызовы имитируются. Обычно выполняется разработчиками.
Интеграционное тестирование — тестирование взаимодействия и связей нескольких компонентов приложения.
Интеграционное тестирование разделяется на следующие виды:
Screen-тестирование (Layout-тестирование) — автоматизированное визуальное тестирование элементов пользовательского интерфейса.
Сквозное тестирование (end2end-тестирование) — тестирование системы в целом с эмуляцией реальной пользовательской среды. Сквозным оно называется, потому что проверяют бизнес-функции системы, при этом развернуто все приложение (ия), без заглушек. То есть, мы тестируем, что с точки зрения конечного пользователя система работает так, как планировалось.
Health-тестирование — тестирование, выполняемое в среде эксплуатации после обновления программного продукта, чтобы убедиться в возможности его дальнейшего использования пользователями.
Для автоматизации мы выбрали два типа из этих пяти: юнит-тесты и интеграционные тесты. Почему? Потому что проводить их в ручном режиме было больнее всего и потому что в этих моментах чаще всего возникали проблемы.
Выбор пути
После осознания того, что мы хотим тестировать, перед нами встал классический вопрос: To be, or not to be? реализовать свое решение или взять уже имеющееся на рынке?
Очевидные плюсы готового продукта — не нужна разработка, есть обширный функционал. Из минусов — нужно разбираться с этой функциональностью, кастомизировать, не исключая шанс, что на все 100% настроить его под себя не получится. Есть риск, что его перестанут поддерживать. Кроме того, часто функционал обширен, а тебе нужно всего 10% от него.
Если же выбрать свой путь, из плюсов — разрабатываешь сам под себя, только то, что нужно, всегда можно докрутить. И поддержка не прекратится, пока тебе самому не надоест. Из минусов — нужна, собственно, разработка.
Честно, мы пробовали оба варианта. Еще до моего прихода в «Спортмастер» команда сделала несколько подходов к имеющимся на рынке решениям, но все они оказались неудачными (не продукты, а попытки). Поэтому выиграла внутренняя разработка. Работа закипела.
Обсуждая, архитектуру хранения нашего механизма для автотестов, мы выбирали между вариантами:
подсистема в рамках основной конфигурации,
набор внешних обработок,
расширение.
К минусам отдельной подсистемы в рамках основной конфигурации можно отнести тот факт, что есть риск по ошибке пронести код автотестов в рабочую среду. Нужна обвязка тестируемых процедур и функций. Кроме того, все тестируемые процедуры и функции должны быть экспортными или писать заглушки с кучей case-ов.
Если рассматривать внешние обработки, то здесь те же самые обвязки, тот же экспорт, но к ним еще добавляется проблема хранения истории изменения наборов обработок. Можно, конечно, Git подключить, но зачем, если можно этого не делать. Или сделать, но на более поздних этапах для code-review и SonarQube.
Чтобы не быть голословным, вот кусочек кода из типовой конфигурации с обвязками для автотестов. Такой код захламляет основной, добавляет сложности логики, да просто может стать очередным местом багов.
Идеальным мы сочли вариант с расширениями. Расширения хранятся отдельно, соответственно, пронести по ошибке уже не получится. Они поддерживают механизм хранилища.
Можно относиться к хранилищу 1С, как угодно, но все-таки это хороший стабильный функционал, которым можно пользоваться для групповой разработки и хранения истории. И один из самых важных пунктов — есть аннотации «Вместо» и «После». «Вместо» мы используем для интеграционных тестов, «После» — для юнит-тестов. И тут нам уже не нужен никакой экспорт.
Тестовый и рабочий контуры
Чтобы наглядно показать, да и самим не забыть, как устроена схема разработки в нашем подразделении, я набросал небольшую схему тестового контура:
Разработчик на своей базе пишет код, тестирует его, там же может запустить автотесты. Завершив отладку и предварительное тестирование, он кладет основной код в хранилище разработки, а код автотестов — в хранилище расширения автотестов. Далее при передаче кода в code-review происходит автопронос его на тестовую БД. Тестировщик, осуществляющий ручное тестирование, проводит тестирование на тестовой БД.
Кроме того, на тестовом контуре есть отдельная конфигурация для запуска автотестов раз в день. И все в ней обновляется в автоматическом режиме. Также прикручен SonarCube, который выполняет статический анализ нашего кода.
Вот как выглядит рабочий контур:
Разница с предыдущей в том, что из хранилища разработки посредством рабочей базы мы руками переносим в рабочее хранилище код, который необходимо накатить на рабочую базу, но который пока не обновили через F7. Запускаются автотесты. После проверки доступных структур, если все ОК, можно обновлять конфигурацию базы данных.
Описание механизма
Это основная обработка по запуску автотестов. Из интересного здесь — дерево тестов. На верхнем уровне тип теста — интеграционный или юнит. Уровнем ниже следуют типы объектов: справочники, документы и регистры. А на последнем уровне находятся сами имена тестов.
Поскольку мы начинали автоматизацию с интеграционных тестов, уместным показалось хранить эти тесты пообъектно.
Вот схема работы обработки по запуску автотестов.
Сначала строится дерево автотестов, далее мы обегаем его, и перед запуском конкретного теста получаем его входные параметры. И начинаем транзакцию.
После начала транзакции начинаем готовить базу к тестам: добавляем, изменяем или удаляем данные в зависимости от того, что в данный момент требуется. Выполняем тест, получаем результат и отменяем транзакцию для того, чтобы база вернулась в исходное состояние. В финале передаем в основную обработку результаты выполнения.
Перейдем к составным частям расширения.
Основные части общего расширения — это обработка по запуску, обработок с автотестами, общие модули для служебных функций и процедур, подсистема для отображения и справочник для формирования наборов данных в предприятии. А вот в расширении конкретной конфигурации хранятся сами обработки с автотестами, макеты с тестовыми и эталонными данными, плюс модули тестируемых объектов. В основном это модули менеджеров, но вообще это могут быть любые модули. Разделение расширение на 2 части вызвано архитектурными тенденциями. Мы стараемся не делать монолитов (получается не всегда), а выделять функциональную область в отдельную конфигурацию на базе единой библиотеки (аналог БСП, просто постарше). Аналогичный подход решили сразу применить к расширению для тестирования. Общая часть — универсальная и единая с общим репозиторием, коллективной разработкой и одним ответственным. Плюс уникальные части для каждой конфигурации, которые используют общую часть.
Вот пример копии модуля менеджера, который хранится в расширении любого типичного справочника или документа.
ВернутьСписокАвтотестов () — возвращает список автотестов текущего объекта
ВернутьНастройкиТеста () — возвращает параметры текущего автотеста
ЮТ_ПолучитьДанныеОракля () — перехватывает обращение к Oracle и подменяет данные своими из макета, при необходимости сверяет структуры
ЮТ_СозданиеИзменениеПрошлоКорректно () — проверяет корректность записи данных в БД
Перейдем к самим тестам.
Интеграционные тесты
Наши основные интеграции:
БД Источник