Добрый день! Меня зовут Александр Капралов, я работаю в компании 1С-Рарус. Я расскажу не только об инструменте для Unit-тестирования, но и вообще, как я дошел до необходимости и желания что-то тестировать.
Немного о себе:
- начинал я работать во франчайзинге;
- какое-то время поработав, понял, что хочу прийти в фирму «1С» и сделать конфигурацию ЗУП лучше, после чего работал там 8 лет над всеми зарплатными решениями, в том числе и над зарплатными библиотеками, которые входят в другие решения, такие как БП, УПП, ERP;
- поработав достаточно долго в фирме «1С», я перешел в Рарус, чтобы, наконец, внедрять ЗУП на корпоративном рынке, потому что некоторые партнеры любили мне рассказывать, что я ничего не понимаю: «ЗУП вообще невнедряемая, сходите, сами попробуйте»;
- я попробовал: у нашей команды есть, в частности, два «Проекта года» по ЗУП – в центре Хруничева и на Уралхиме.
Технические задачи внедрения
Когда мы приходим внедрять, у нас:
- самая главная задача – это сделать клиенту те доработки, которые ему необходимы;
- при этом для нас очень важно, чтобы типовая функциональность продолжала работать – считались зарплата, налоги;
- и, конечно же, мы хотим заработать денег и не хотим делать себе в убыток.
Процессы внедрения у нас, в принципе, достаточно хорошо оптимизированы. Мы четко придерживаемся бюджета и стараемся укладываться в сроки – не выходим за рамки денежных лимитов, которые выставляем заказчику
Мы хотим внедрять новые технологии, но это очень тяжело, потому что мы не можем взять и внедрить что-нибудь новое – если это будет медленно, мы начнем срывать сроки, или произойдет перерасход бюджета. Поэтому осваивать новые технологии приходится аккуратно.
Новая среда разработки
В частности, я стал смотреть на новую среду разработки EDT. Про нее на конференции уже много раз говорили:
- EDT – это проект на базе Eclipse, фактически, набор плагинов;
- EDT работает с конфигурацией, как с набором файлов;
- у нее есть некоторые преимущества по отслеживанию истории разработки в Git – про это вроде рассказывали уже много раз, но, на мой взгляд, не сказали важную вещь, что при использовании каких-то веб-интерфейсов, например, GitLab, можно легко администрировать репозиторий. И вообще не сравнить по скорости и по простоте с тем, как добавить новое хранилище HTTP для работы в обычном конфигураторе;
- в EDT есть рефакторинг – функция, которая помогает нам при переименовании или удалении объектов внести изменения в конфигурацию;
- есть расширенная контекстная подсказка, которая помогает подбирать свойства каких-нибудь структур – мы совершаем намного меньше ошибок;
- и продвинутые проверки – в частности, BSL Language Server, который позволяет «на лету» отсеивать сразу очень много ошибок.
- и конечно, самое важное, на мой взгляд – это возможность написания своих плагинов для расширения возможностей конфигуратора.
Особенности EDT
При этом у EDT есть некоторые особенности:
- Самое главное – это высокие системные требования. Когда мы используем EDT в DevOps, нам необязательно иметь какие-то мощные машины – мы запустили ее где-то на сервере, она поработала, выдала ошибки. Но если же мы начинаем разрабатывать на EDT, то никуда не деться, приходится апгрейдить компьютеры:
- в первую очередь, это высокие требования по памяти – 16 Гб;
- SSD-диск обязательно;
- мощный процессор.
- Надо понимать, что EDT работает с конфигурацией (с информационной базой) через агент конфигуратора.
- Поэтому EDT это не замена конфигуратора, это такой продукт, который через конфигуратор добавляет в разработку на 1С некоторые удобства. Поэтому, конечно, нужно осторожно подходить к тому, можно ли вообще перевести разработку на EDT.
Плагины для EDT. TDD, JUnit и 1С
Я решил попробовать сам разрабатывать плагин.
- Изначально у меня была мысль просто облегчить себе доработку – допустим, я добавляю какой-нибудь объект (например, документ), он анализирует конфигурацию, смотрит, что у меня используются какие-нибудь БСП-ные подсистемы – например, версионирование, свойства, контактная информация, RLS, и добавляет нужные объекты. Т.е. у меня изначально была мысль просто написать какой-то помощник работы с метаданными.
- Я стал что-то такое делать, попутно изучая Java (до этого я этот язык не изучал), и когда я написал что-то работающее, стал вопрос – как это вообще проверить? Я же работаю с метаданными, я же сломаю что-нибудь, меня же мои коллеги и повесят вместе с EDT на ближайшем суку.
- Соответственно, я пошел к старшим товарищам и спросил: «Как вы в Java тестируете свои доработки?» Они мне говорят: «Саша, прочитай книгу "Разработка через тестирование", там все доступно написано». Я прочитал книгу, и она мне очень понравилась. Что хорошо – там автор не просто говорит, как тестировать, а он высказывает ход своих мыслей, говорит: «Это я делаю по такой-то причине, а это – по такой-то причине». Соответственно, можно взять Eclipse, и прямо по книжке все приведенные в ней примеры сделать.
- Когда я начал пробовать разработку через TDD, мне это понравилось. И я осознал, что именно это мне нужно в 1С для того, чтобы повысить качество.
- При этом в 1С я изначально, как и все остальные внедренцы, вел разработку через отладку: написал код, запустил отладчик, поставил точку останова, посмотрел значения переменных, проверил, что движения записались в набор записей и проверил, что это выглядит удовлетворительно. Вот такая разработка через отладку.
- Стал смотреть, можно ли делать разработку через тестирование в 1С и выяснил, что инструментов для этого нет. Я хотел сделать, как в Java – нажал кнопку, минуту подождал, через минуту получил – красную лампочку или зеленую.
- Соответственно, поскольку таких инструментов не было, я стал думать – можно ли сделать их самому.
- Но при этом мне хотелось использовать существующие технологии, я не хотел писать все с нуля, не собирался переквалифицироваться в Java-разработчика.
Концепция Unit-тестирования в 1С
Для этого я разработал некую концепцию, как мое решение могло бы выглядеть.
Я думал, что тесты могут выглядеть так – я создаю расширение, в нем создаю общий модуль, в этом общем модуле пишу какие-то тесты. Дальше запускаю пустую базу в режиме «1С:Предприятие», предприятие само запускает мои тесты, выполняет, и после этого я вижу результат в EDT – зеленая или красная лампочка.
Почему я выбрал расширение?
- Во-первых, в расширение можно поместить много модулей и хранить их отдельно от конфигурации – когда мы выдаем решение заказчику, ему вряд ли понравится, что там содержатся какие-то тесты.
- При этом есть возможность хранить эти тесты в хранилище, версионировать, держать все связанные изменения в одном месте.
- Так как расширение позволяет вызывать функции без конструкции Экспорт, я могу тестировать не только публичный программный интерфейс, но и какие-то внутренние функции, которые недоступны извне.
- Ну и благодаря тому, что это общий модуль, мы можем выставлять у него, что он клиентский или серверный, или клиент-серверный. И тем самым, управлять, где мы вообще хотим проверять наши тесты – на клиенте или на сервере.
- И для тех, кто знаком с Java, это аналог бандла-фрагмента.
Сам Unit-тест, по моему мнению, выглядит достаточно просто:
- мы берем какую-функцию, вызываем ее, смотрим результат;
- сравниваем результат с эталоном;
- и фиксируем результат сравнения – показываем, что у нас выполнилось, а что не выполнилось.
Я придумал, что мои тестовые процедуры будут выглядеть вот так:
- специальный комментарий // @unit-test, который пишется перед процедурой;
- у этой процедуры единственный обязательный параметр для вызова специальных функций тестирования;
- тестовая процедура должна быть экспортной;
- при этом в комментарии @unit-test можно указать дополнительный тег, который позволяет нам какие-то тесты выделять – если мы захотим запускать не все тесты, которые есть в модуле, а только определенные. Например, когда я вижу, что у меня какой-то тест падает, я его помечаю отдельным тегом и дальше проверяю только его.
Самый простой вариант теста:
- мы вызвали функцию;
- посмотрели результат;
- если результат нас не устроил – вызвали исключение.
Тогда в EDT появляется такой диалог – он состоит из двух частей.
- На верхней картинке показана левая часть диалога – список всех процедур, которые я тестировал. Галочка – это хорошо, крестик – плохо. Есть возможность отключить «галочки», и показывать только функции с крестиком.
- Если выбрать конкретную функцию, то можно увидеть, почему она не выполнилась. В данном случае здесь отображается тот текст исключения, который я указал. Плюс – стек вызовов. Можно посмотреть, где именно функция упала.
Фреймворк, который запускает Unit-тестирование
При этом, конечно, фреймворк, который занимается тестированием, предоставляет некоторые специальные функции, которые позволяют конкретизировать суть теста – показывают, что мы проверяли изначально. Не просто, что что-то упало, а мы проверяли, что значение булево должно быть Истина, а оно – Ложь.
Если щелкнуть на сообщение: «Переданный параметр (ложь) не является Истиной», откроется диалоговое окно.
Это диалоговое окно позволяет нам увидеть различия более предметно. Например, если мы сравниваем строки или файлы. Текстовые файлы – это тоже просто многострочный текст. Мы можем сразу увидеть, в какой именно части у нас расхождения.
Также мы можем проверить коллекции – таблицы, списки значений, массивы и т.д. Раньше нам в отладчике приходилось открывать эту панель, выводить два списка в макеты, удалять ненужные строки, потом глазами сравнивать и т.д. А здесь нажал и плагин сразу нам автоматически показал различия – искать их больше не нужно.
Вообще функций у фреймворка очень много. Самое главное, на что хочется обратить внимание – когда мы пишем тесты, нам важно не только знать, что наша функция работает, но также протестировать, как она будет себя вести, если у нас переданы неправильные параметры, или что-то не прочиталось. В общем, обязательно важно тестировать еще и на падения.
Для этого, опять же, в фреймворке есть специальные функции. Обычно они начинаются с «ПроверитьНе». Например, «ПроверитьНеРавенство».
- Например, мы можем использовать функцию «ПроверитьМетодВыполнился» или функцию «ПроверитьМетодНеВыполнился». Если мы проверяем, что метод не выполнился, то ошибка, которую вернет нам метод, должна соответствовать ровно той, которую мы ожидаем. Например, если у нас ошибка формируется на базе параметров, то мы можем проверить, что передав какие-то параметры, мы получим именно то сообщение об ошибке, которое ожидаем.
- Либо мы можем просто проверять выполнимость кода функцией «ПроверитьВыполнилось» – если мы составляем какую-то сложную функцию, чтобы убедиться, что она вообще работает.
Отдельная история – это проверка асинхронных вызовов. ИТС нам говорит, что если вы выполняете код на клиенте, он должен быть асинхронным. В частности, если мы передаем файлы, то с помощью веб-браузера мы можем передать их только в асинхронном режиме.
И тут, конечно, есть некоторые особенности. При запуске тестов фреймворк тестирования их просто выполняет – он, в принципе, не знает о том, что у нас пошел какой-то асинхронный вызов.
- Чтобы протестировать асинхронный вызов есть специальная команда «ЗапретитьВыполнениеШагов». Когда мы ее вызываем, фреймворк просто ждет, что мы к нему вернемся и дадим команду работать дальше.
- Пока он ждет, мы готовим наши данные, вызываем наш асинхронный вызов и передаем туда обязательно переменную «Фреймворк», чтобы потом через нее дать команду работать дальше.
- Когда у нас пришло завершение асинхронного вызова – мы получили файлы, сложили их на сервер, выполнили какие-то проверки, вернулись на клиент.
- С помощью специального шага «ДобавитьОшибкуСценария» мы можем вывести пользователю ошибки.
- И с помощью функции «ПродолжитьВыполнениеШагов» продолжаем выполнение шагов дальше.
Еще одна особенность – мы не можем в асинхронных вызовах использовать ВызватьИсключение, потому что ВызватьИсключение не перехватывается фреймворком тестирования. Тест просто упадет, и дальше ничего работать не будет.
Расширение 1С, содержащее примеры работы с фреймворком Unit-тестирования
Для облегчения понимания я написал расширение в формате EDT, в котором можно посмотреть, как работают все эти функции фреймворка. Его можно скачать из репозитория по адресу https://github.com/DoublesunRUS/ru.capralow.dt.unit.launcher/tree/master/МодульныеТестыVA, запустить и увидеть результат – выполнение или невыполнение.
Для этого нужно использовать платформу 8.3.12 (или выше) и последний релиз EDT.
Запуск теста
Как происходит запуск теста?
Если вы уже пользовались EDT, то запуск теста происходит примерно так же, как вы запускаете «1С:Предприятие». В вариантах запуска отладки есть специальный раздел, называется «Модульные тесты», в котором вы можете создать отдельную конфигурацию, где просто дополнительно указываете, тесты из какого расширения вы хотите запустить:
- либо все тесты из расширения целиком;
- либо конкретный общий модуль расширения;
- либо тесты с конкретным тегом.
После этого запускаете.
Про Vanessa Automation сегодня уже говорили – это замечательная обработка. К счастью для меня она умеет еще и юнит-тесты.
- Этот инструмент делает всю работу по тестированию – я нарадоваться не могу.
- Он запускает тесты последовательно, формирует нам результат и сообщение об ошибках.
- Он выполняется в момент запуска режима «1С:Предприятие», но если у вас тесты маленькие и простые – вы этого даже не заметите. А если в типовую редакцию еще и включено отображение рекламы, то оно покажется выше обработки – вы просто не узнаете, что она у вас есть. Но при этом сделать ее незаметной, чтобы снизить порог вхождения, и было целью. Поэтому Vanessa Automation включена в поставку плагина – вам не нужно ее скачивать, следить за выходом релизов.
- И она автоматически настроена так, чтобы юнит-тесты запускались максимально эффективно.
Непрерывная интеграция (CI)
После того, как вы разработали тесты, конечно же, наша цель – повысить качество. Поэтому предполагается, что все разработчики сначала разработали свои юнит-тесты, затем сложили их в Git, а дальше уже юнит-тесты запускаются в рамках DevOps-процедур. Идея такая:
- разработчик кодирует функциональность в своей ветке;
- затем, когда он закончил, он помещает ветку в Dev;
- автоматически запускаются все юнит-тесты всех разработчиков;
- если все хорошо, они помещаются в ветку master;
- после этого происходит создание cf-файла или файла поставки (или, как некоторые любят, просто выгрузил cf – это билд, а загрузил cf – это уже деплой).
В таком виде это все тоже прекрасно работает.
Опять же, сегодня много рассказывали про Jenkins. Но мне кажется, что если вы не пишете сценарные тесты, не готовы изучать Jenkins, но при этом у вас есть GitLab, то вам просто достаточно GitLab Runner.
- GitLab Runner тоже умеет запускать тестирование при помещении файлов 1С в Git;
- все, что вам нужно – это создать командный файл .yml;
- в yml-файле разместить команды для запуска «1С:Предприятие» и Vanessa Automation;
- и по окончании запуска выгрузить результат в Allure Report или SonarQube.
Vanessa Automation умеет выгружать результаты в том виде, в котором их будет понимать SonarQube. Это позволит совместно с другими операциями и другими проверками повышать качество своего внедрения.
Где взять плагин
Где взять плагин:
- Исходники плагина можно скачать на GitHub по адресу https://github.com/DoublesunRUS/ru.capralow.dt.unit.launcher.
- Чтобы установить плагин в EDT, надо скопировать адрес http://capralow.ru/edt/unit.launcher/latest/ и вставить в специальный диалог «Справка» – «Установить новое ПО»;
- С помощью Vanessa Automation мы записали видеоролик, где Яндекс.Алиса вам расскажет, как установить этот плагин – вам даже не нужно задумываться, повторили за Алисой, и все у вас получится.
Как разрабатывать плагины
Если вы впечатлились возможностями EDT и хотите начать писать свои плагины (не обязательно для тестирования, может быть, для проверки или чего-нибудь еще), то это сделать достаточно просто:
- Вам необходима целевая платформа https://github.com/1C-Company/dt-example-plugins/tree/master/simple-plugin/target. Целевую платформу распространяет сама фирма 1С, она лежит в репозитории компании 1С на GitHub, вы можете ее оттуда скачать. Но надо понимать, что она скачивается с сайта https://partners.v8.1c.ru/, и если у вас нет доступа к этому сайту, то разрабатывать плагины вы не сможете.
- Даже если вам кто-то один раз логин ввел, и вы таргет-платформу скачаете, чтобы разрабатывать – собрать плагин без доступа к партнерскому сайту фирмы «1С» вы тоже не сможете. Плагин собирается с помощью Maven по инструкции https://github.com/1C-Company/dt-example-plugins/blob/master/simple-plugin/README.md, и во время сборки он снова попросит логин с паролем. Нет логина с паролем – ничего не получится.
Когда вы разрабатываете плагин в EDT, вызвать затруднения может только специфика, связанная с работой с метаданными:
- Основную часть по написанию плагинов можно посмотреть для обычного Eclipse – в интернете очень много информации.
- Даже я, незнакомый с Java, просто брал готовые примеры разработки плагинов, заменял фамилию разработчика в исходниках, и все работало.
Есть документация от разработчиков EDT, она находится в указанной папке. И ставится автоматически, когда вы скачиваете EDT. Поставили EDT, она там есть.
- Документация не обновляется, но она достаточно актуальна, просто потому, что разработчики стараются не менять публичные интерфейсы.
- Вы всегда можете задать свои вопросы по разработке плагинов для EDT на партнерской конференции. Я это делаю регулярно. Разработчики оперативно отвечают, ищут возможности реализовать то, что нужно.
- Есть telegram-канал https://t.me/EDTplugin – там нет разработчиков, но есть плагинописатели.
Результаты
Хочется, конечно, поделиться результатами.
- Во-первых, я сам использую свой плагин – у нас внедрение ЗУП идет 9 месяцев, женщины за это время ребенка рожают, а мы за это время рожаем нетиповую ЗУП. При этом релизы типового ЗУП выходят очень часто (каждые две недели), и процесс перехода на новую версию в момент разработки всегда очень болезненный, ведь, с одной стороны. у нас сроки – нам уже нужно сдавать проект, и если мы сейчас обновимся, у нас в результате что-то перестанет работать. Не выдержим сроки – будут штрафные санкции. Но благодаря юнит-тестам, которые я запускаю, я теперь после обновления релиза точно могу сказать, сломалось у меня что-то или нет. Я запустил и сразу увидел количество ошибок. Самое главное, я могу еще и оценить, сколько мне потребуется времени на то, чтобы устранить доработки – если я увижу, что доработки потребуются серьезные, я могу сказать своему руководителю проекта, что если мы обновимся на новый релиз сейчас, мне потребуется неделя на адаптацию.
- Когда я начал делать тесты, выяснилось, что все мои процедуры надо перерабатывать. Дело в том, что у меня были большие функции, которые делают все – я не могу их протестировать в один прием. Я не могу передать такой набор параметров, чтобы выполнить эту функцию частично, и посмотреть результат – приходилось делить, в том числе для того, чтобы избавиться от вариативности.
- Выяснилось, что настройка параметров – это один кусок кода, а потом по настроенным параметрам достаточно один раз запустить какую-то процедуру, протестировать ее – нет необходимости запускать несколько раз. Благодаря тому, что я выделил отдельную функцию, у меня появилась возможность тестировать еще в тех вариантах, которые я раньше вообще никогда не тестировал. Это к вопросу о когнитивной сложности, про которую рассказывал в своем докладе Олег Тымко. В BSL Language Server есть замечательная проверка – когнитивная сложность, показатель того, насколько легко вам понять, что делает процедура, если вы просто смотрите на нее глазами. По умолчанию когнитивная сложность = 15. Избавиться от этой когнитивной сложности очень тяжело. Я знаю, что некоторые люди просто сразу ставят когнитивную сложность = 500, считая, что бороться с этой проблемой не нужно. Но если вы будете разрабатывать процедуры с мыслью «как мне ее протестировать», тогда у вас не будет проблем с когнитивной сложностью, потому что очень быстро выяснится, что именно в таком варианте когнитивной сложности нет.
- Если я задаю какие-то параметры, а после этого запускаю автоматический тест, мне не доставляет сложности добавить еще десяток-другой параметров и посмотреть – что будет. На падение легко теперь тестировать. Если раньше, когда я кодировал и боялся – вдруг она упадет, мне переделывать нужно будет, то теперь я могу проверить, и если она упадет, сразу поправить. Конечно же, я нашел ошибки в том коде, который я считал идеальным, в котором нечему ломаться вообще никогда. Теперь мне придется с этим жить.
- Самое главное – перейти от разработки через отладку к разработке через тестирование оказалось достаточно легко. Нужно просто запустить нужные тесты вместе с отладкой. Как только тебе захотелось где-то поставить точку останова в отладчике, и что-то посмотреть, ты просто описываешь эти значения себе в виде теста, и запускаешь их автоматически. В таком варианте создавать юнит-тесты оказалось очень просто.
Я надеюсь, что теперь мои внедрения, и ваши тоже, станут гораздо проще. Вы сможете их делать быстро, качественно и дорого. Это мое вам пожелание.
****************
Данная статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART EVENT 2019.
Приглашаем на конференции Инфостарта 2025 годаINFOSTART TEAMLEAD EVENT
Не только для разработчиков, но и для руководителей отделов разработки, тимлидов и ИТ-директоров. INFOSTART A&PM EVENT (Анализ & Управление проектами)
Практическая конференция для аналитиков и руководителей проектов 1С. |