Юнит тестирование в 1С.
Модульное тестирование (или юнит-тестирование) — это процесс проверки отдельных модулей программного обеспечения на предмет их корректности.
Модуль в этом контексте представляет собой небольшую, изолированную часть программы, такую как функция, метод, класс или объект, которая выполняет определённую задачу или функцию в приложении.
Цель модульного тестирования — убедиться в том, что каждый модуль работает правильно и соответствует спецификациям. Этот метод позволяет выявить и исправить ошибки на ранних этапах разработки, что упрощает процесс отладки и обеспечивает более надёжное программное обеспечение.
Плюсы юнит-тестирования, которые я выявил:
- Можно легко и быстро проверить какую-либо процедуру или функцию
- При написании теста часто бывает так, что такой похожий необходимый метод уже есть, и он покрыт тестом, остается только переиспользовать.
- Улучшается качество кода
- Часто ошибки в коде выявляются на этапе как раз юнит-тестирования до отправки на проверку тестировщику или заказчику
- Оперативное выявление ошибок
- Возможность тестировать бизнес логику
- Позволяет вести разработку через тестирование (TDD)
Коротко о TDD
TDD - разработка через тестирование, сначала пишет тесты, потом пишем код под эти тесты, после успешной прогонки тестов код считается готовым.
Некоторые замечания при работе по TDD:
- Сложно, прям очень сложно перестроиться с привычного стиля программирования, но это возможно.
- Получается быстро находить ошибки и исправлять их так как тест обычно пишется под небольшой кусочек кода.
- Уверенность в качестве кода
- Перед написанием кода сначала думаешь как лучше спроектировать то или иное решение, опять же чтобы и тестами было удобно покрыть и данные сгенерировать для теста.
- Тесты позволяют создавать слабосвязанные методы, так как тест сложно наложить на сильно взаимосвязанные методы нам просто приходится их упрощать, делать обособленными.
- Отладка, отладчик, точки останова и т. п. теперь не нужны.
- Отсутствует дублирование кода
YAxUnit
За YAxUnit спасибо Кирилкину Дмитрию, он нам открыл эту замечательную вещь.
YAxUnit представляет собой мощный инструмент написания тестов для решений на платформе 1С:Предприятие.
Подробнее можно почитать здесь: https://bia-technologies.github.io/yaxunit/
Что мы сделали
YAxUnit представляет собой расширение, поэтому мы создали для себя хранилище для расширения, чтобы можно было заниматься коллективным созданием тестов.
Простые правила при написании тестов:
- Называть общие модули «ОМ_» + Название метаданного
- Метод теста обзывать «Тест_» + имя метода в основной конфигурации
- Напротив покрытого теста ставить комментарий «Покрыто юнит-тестом»
- Код необходимо выносить либо в модуль менеджера либо в общие модули, можно, в том числе, и в клиентские
Примеры Тестов
Приведу 3 примера: простой и посложнее. И тест, который отрабатывает, но есть нюанс.
- Простой пример - есть потребность передать для обработки введенный пользователем путь к файлу без кавычек.
Пишем простенький тест на клиенте:
Процедура ИсполняемыеСценарии() Экспорт
ЮТТесты
.ДобавитьКлиентскийТест("Тест_СократитьДвойныеКавычки");
КонецПроцедуры
Процедура Тест_СократитьДвойныеКавычки() Экспорт
СтрокаСКавычками = """СтрокаСКавычками""";
СтрокаБезКавычек = АвтоматизацияКлиент.СократитьДвойныеКавычки(СтрокаСКавычками);
ЮТест.ОжидаетЧто(СтрНайти(СтрокаБезКавычек, """",) = 0);
ЮТест.ОжидаетЧто(СтрокаБезКавычек).ИмеетТип("Строка");
КонецПроцедуры
Пишем код:
Функция СократитьДвойныеКавычки(Знач Значение) Экспорт
Пока СтрНачинаетсяС(Значение, """") Цикл
Значение = Сред(Значение, 2);
КонецЦикла;
Пока СтрЗаканчиваетсяНа(Значение, """") Цикл
Значение = Лев(Значение, СтрДлина(Значение) - 1);
КонецЦикла;
Возврат Значение;
КонецФункции
Запускаем тест:
Код и тест готовы.
Еще простой пример - необходимо проверить правильность перевода значений характеристик сторонним сервисом и работоспособность.
Процедура Тест_ПолучитьТелоПереводаСтрокиHTTP() Экспорт
РегистрМенеджер = РегистрыСведений.СинонимыХарактеристикСопровождения;
ЭталоноеТелоЗапроса = Новый Структура;
МассивЯзыков = Новый Массив;
МассивЯзыков.Добавить("en");//kk
МассивЯзыков.Добавить("he");//en
МассивЯзыков.Добавить("kk");//he
ЭталоноеТелоЗапроса.Вставить("languages", МассивЯзыков);
values = Новый Массив;
ПереводимыеЗначения = Новый Структура;
ПереводимыеЗначения.Вставить("type", "Цвет");
ПереводимыеЗначения.Вставить("value", "");
values.Добавить(ПереводимыеЗначения);
ЭталоноеТелоЗапроса.Вставить("values", values);
ЗащищенноеСоединение = новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение("translate-api.dwh.dns-shop.ru",,,,, 30, ЗащищенноеСоединение);
ТелоОтветаJSON = РегистрМенеджер.ПолучитьТелоПереводаСтрокиHTTP(ЭталоноеТелоЗапроса, Соединение);
ЮТест.ОжидаетЧто(ТелоОтветаJSON).ИмеетТип("Строка", "HTTP сервис перестал работать");
ПроверитьКорректностьПеревода(ТелоОтветаJSON);
КонецПроцедуры
Генерируем данные, запускаем тест и пишем процедуру проверки данных
Процедура ПроверитьКорректностьПеревода(ТелоОтветаJSON)
ОбъектЧтениеJSON = Новый ЧтениеJSON;
ОбъектЧтениеJSON.УстановитьСтроку(ТелоОтветаJSON);
РезультатЧтения = ПрочитатьJSON(ОбъектЧтениеJSON, Истина);
ОбъектЧтениеJSON.Закрыть();
Для Каждого МассивПоСтроке ИЗ РезультатЧтения Цикл
Для Каждого СоответствиеЯзыкаПоСтроке ИЗ МассивПоСтроке Цикл
value = СоответствиеЯзыкаПоСтроке.Получить("value");
type = СоответствиеЯзыкаПоСтроке.Получить("type");
language = СоответствиеЯзыкаПоСтроке.Получить("language");
Если language = "ru" Тогда
Продолжить;
КонецЕсли;
Если language = "en" Тогда
ЮТУтверждения.Что(type, СтрШаблон("Значение 'Цвет' было переведенно как %1 на Английском", type))
.ИмеетТип(Тип("Строка"))
.Равно("Color");
КонецЕсли;
Если language = "kk" Тогда
ЮТУтверждения.Что(type, СтрШаблон("Значение 'Цвет' было переведенно как %1 на Казахском", type))
.ИмеетТип(Тип("Строка"))
.Равно("Тw9;с");
КонецЕсли;
Если language = "he" Тогда
ЮТУтверждения.Что(type, СтрШаблон("Значение 'Цвет' было переведенно как %1 на Иврите", type))
.ИмеетТип(Тип("Строка"))
.Равно("צבע");
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Далее пишем не сложный метод и запускаем тест.
Метод работает верно.
- Пример посложнее - отчет рабочее пространство менеджера ВЭД, по кнопке "Сформировать" получаем данные для отчета, далее требуется применить фильтр по полю "Заявка на стикеровку" и на основании фильтра вывести обновленную результирующую таблицу.
Условие по ТЗ:
Нам нужна потребуется проформа, на основании проформы заявка на сопровождение, заявка на стикеровка с составом на основании проформы.
Сгенерируем данные, добавим их к текущей таблице с данными, запустим метод фильтрации данных, ждем на выходе необходимый результат.
Генерируем данные:
Товар1 = ЮТест.Данные().СоздатьЭлемент(Справочники.Номенклатура,,, Новый Структура("ОбменДаннымиЗагрузка", Истина));
Товар2 = ЮТест.Данные().СоздатьЭлемент(Справочники.Номенклатура,,, Новый Структура("ОбменДаннымиЗагрузка", Истина));
Проформа = ЮТест.Данные().КонструкторОбъекта(Документы.Проформа)
.Установить("Проведен", Истина)
.ФикцияОбязательныхПолей()
.ТабличнаяЧасть("Состав")
.ДобавитьСтроку()
.Установить("Товар", Товар1)
.Фикция("Количество")
.Фикция("Цена")
.ДобавитьСтроку()
.Установить("Товар", Товар2)
.Фикция("Количество")
.Фикция("Цена")
.Записать(, Истина);
ЗаявкаНаСопровождение = ЮТест.Данные().КонструкторОбъекта(Документы.ЗаявкаНасопровождение)
.Установить("Проведен", Истина)
.Установить("ДокументОснование", Проформа)
.ФикцияОбязательныхПолей()
.ТабличнаяЧасть("Состав")
.ДобавитьСтроку()
.Установить("Товар", Товар1)
.Установить("ЗнСт", ЛОЖЬ)
.ДобавитьСтроку()
.Установить("Товар", Товар2)
.Установить("ЗнСт", ЛОЖЬ)
.Записать(, Истина);
ЗаявкаНаСтикеровку= ЮТест.Данные().КонструкторОбъекта(Документы.ЗаявкаНаСтикеровку)
.Установить("Проведен", Истина)
.ФикцияОбязательныхПолей()
.ТабличнаяЧасть("Состав")
.ДобавитьСтроку()
.Установить("Товар", Товар1)
.Установить("ОснованиеКорневое", Проформа)
.ДобавитьСтроку()
.Установить("Товар", Товар2)
.Установить("ОснованиеКорневое", Проформа)
.Записать(, Истина);
Таблица = Таблица.Таблица;
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.Проформа = Проформа;
НоваяСтрока.Товар = Товар1;
НоваяСтрока.Количество = 1;
НоваяСтрока.ЗаявкаНаСопровождение = ЗаявкаНаСопровождение;
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.Проформа = Проформа;
НоваяСтрока.Количество = 1;
НоваяСтрока.Товар = Товар2;
НоваяСтрока.ЗаявкаНаСопровождение = ЗаявкаНаСопровождение;
сткДанные.Вставить("Таблица", Таблица);
Получаем таблицу с данными
- Создаем товары
- Создаем проформу, добавляем в состав товары
- Создаем заявку на сопровождение, в основании указываем проформу, в состав реквизит ЗнСт выставляем в ложь и добавляем товары из проформы
- Создаем заявку на стикеровку, в составе указываем товары и в корневое основание нашу проформу
- Добавляем данные в таблицу и заполняем параметр для вызываемой функции
- Указываем, какой отбор необходимо проверить
сткПараметры.Вставить("УсловиеЗнСт", "НЕ втДанные.ТребуетсяЗаявкаНаСтикеровкуУровеньЗнСп");//Проверяем этот отбор
- Вызываем метод и ждем в итоговой таблице 2 строки с нашими данными
РезультирующуаяТаблица = Отчеты.РабочееПространствоМенеджераВЭД.ПолучитьДанныеСУчетомОтбора(сткПараметры);
НайденныеСтроки = РезультирующуаяТаблица.НайтиСтроки(Новый Структура("ЗаявкаНаСопровождение, Проформа", ЗаявкаНаСопровождение, Проформа));
ЮТест.ОжидаетЧто(НайденныеСтроки.Количество() = 2);
- Добавляем в запросе метода необходимой блок запроса и запускаем тест
- Также есть тест для проверки обработки файла Excell который в момент написания работал отлично и быстро, но в какой – то момент что-то произошло и метод стал выполняться долго, что было сразу обнаружено при прогонке тестов.
В дальнейшем есть планы все это дело автоматизировать, а именно автоматическое обновление нашего клона, автоматический запуск тестов на клоне и отправка результатов в телеграмм.
Спасибо за внимание.