Дымовые тесты для забывчивых/торопливых

Инструменты для реализации дымовых тестов по метаданным конфигурации. И примеры.

 

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

На устоявшихся конфигурациях таких изменений по добавлению нового функционала — достаточно мало. Но вот появилась задача по разработке еще одной конфигурации… К тому же, частенько интересовало, как самому написать дымовой тест — здесь имеются в виду TDD-тесты для xUnitFor1C/ADD.

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

  • Проверка доступности Чтения сохраняемых данных (док-тов, справочников и т.п.) для ролей без расширенных полномочий
  • Проверка установки свойства РежимУправленияБлокировкойДанных в значение, установленное для самой конфигурации

Вторая задача, на самом деле, носит больше академический характер. Но для выработки инструментов — вполне себе подходит.

Поехали

Как устроен дымовой тест — смотрим в реализации от Silverbulleters,  estssmokeтесты_ОткрытиеФормКонфигурации. Видим, что для наших задач все сводится к вызовам:

ПараметрыТеста = НаборТестов.ПараметрыТеста(...)

и 

НаборТестов.Добавить(ИмяПроцедурыОбработчика, ПараметрыТеста, ЗаголовокТеста)

Ок. Поехали далее

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

И вот плагин написан (кто не в курсе, это обычная внешняя обработка, только с определенными типовыми методами). Называется ИтераторМетаданных. Его интерфейс описан далее.

Свойства:

  • ДопустимыеМетаданные (СписокЗначений). Заполняем этот список самими метаданными:
Итератор.ДопустимыеМетаданные.Добавить(Метаданные.Справочники.Контрагенты); // добавление конкретного объекта метаданных
Итератор.ДопустимыеМетаданные.Добавить(Метаданные.Документы); // добавление коллекции метаданных
  • ИсключаемыеМетаданные (СписокЗначений). Заполняем его кодом, аналогичным выше. Либо не заполняем.
  • ДополнятьЗависимымиОбъектами (Булево, Ложь по умолчанию). Можно, например, заполнить ДопустимыеМетаданные только документами. И дополнительно можем установить реквизит ДополнятьЗависимымиОбъектами в значение Истина. И тогда анализироваться будут не только документы, но и регистры, справочники и перечисления, которые участвуют в структуре метаданных документов в виде их реквизитов.

Методы:

  • Процедура Инициализация(…). Это типовой для плагина метод. В нем сбрасываем все настройки Итератора — чистим списки метаданных, сбрасываем ДополнятьЗависимымиОбъектами в Ложь.
  • Функция ДеревоМетаданных(), возвращает ДеревоЗначений. Дерево имеет одно поле ОбъектМетаданных и два уровня. На верхнем уровне (Дерево.Строки) имеем имена коллекций метаданных. Например, Справочник. На вложенном уровне (Дерево.Строки[0].Строки) имеем данные типа ОбъектМетаданных, относящиеся к родительской коллекции.
  • Процедура Перечислить(Источник, ПриСледующемОбъектеМетаданных, ПриСледующемТипеМетаданных = Неопределено)
    • Параметры:
    • Источник — ОбработкаОбъект  — Модуль, в котором будут вызываться процедуры-обработчики событий.
    • ПриСледующемОбъектеМетаданных  — Строка — Имя процедуры-обработчика при переходе на следующий объект метаданных.
    • ПриСледующемТипеМетаданных  — Строка, Неопределено — Имя процедуры-обработчика при переходе на следующий тип объектов метаданных.
    • Интерфейс обработчиков — ПроцедураОбработчик(ОбъектМетаданных) или ПроцедураОбработчик(ОбъектМетаданных, Родитель)

Для построения дерева можно и не заполнять реквизит ДопустимыеМетаданные. В этом случае дерево будет заполнено максимальным количеством метаданных. Для этого используется приватная функция плагина ВсеКоллекцииМетаданных().

Пишем тесты

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

Вариант 1. Тест на чтение Не-Администраторами

Этот вариант задумывался как раз изначально. И, может быть, чуть сложнее, чем будет следующий вариант. В этом тесте будем использовать метод Итератор.Перечислить(…).

В стандартном методе обработки тестирования проинициализируем Итератор:

Процедура Инициализация(КонтекстЯдраПараметр) Экспорт

[Пропущено]

ИтераторМетаданных = КонтекстЯдра.Плагин("ИтераторМетаданных");
ИтераторМетаданных.Инициализация(КонтекстЯдраПараметр);  // Сброс реквизитов плагина. Необходимо сделать, т.к. плагин уже мог быть инициализирован другой тестовой обработкой
ИтераторМетаданных.ДополнятьЗависимымиОбъектами = Истина;   // В принципе, можно и не дополнять. Проверял работу этого флага.

ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.Документы);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.Справочники);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.РегистрыСведений);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.Константы);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.РегистрыНакопления);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.ПланыВидовХарактеристик);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.Задачи);
ИтераторМетаданных.ДопустимыеМетаданные.Добавить(Метаданные.БизнесПроцессы);

// При ДополнятьЗависимымиОбъектами = Истина, в объектах проверки появляются и перечисления.
// Но настройки прав для перечислений - нет. Поэтому Перечисления исключаем.
ИтераторМетаданных.ИсключаемыеМетаданные.Добавить(Метаданные.Перечисления);

КонецПроцедуры

Посмотрим еще раз на интерфейсы callback-процедур для метода Итератор.Перечислить(…) и напишем один интерфейсный метод. Он будет отвечать и за обработку разделов, и за обработку объектов метаданных:

Процедура ПриСледующемОбъектеМетаданных(ОбъектМетаданных, Родитель) Экспорт

ЗаголовокОбщаяЧасть = "Проверка доступа на Чтение Не-Администраторами";
Если Родитель=Неопределено И ТипЗнч(ОбъектМетаданных)=Тип("Строка") Тогда
НаборТестов.НачатьГруппу(ЗаголовокОбщаяЧасть + " " + ОбъектМетаданных);

ИначеЕсли ОбъектМетаданных<>Неопределено Тогда
ПараметрыТеста = НаборТестов.ПараметрыТеста(ОбъектМетаданных, Родитель);
ЗаголовокТеста = "" + ОбъектМетаданных.ПолноеИмя() + ": " + ЗаголовокОбщаяЧасть;
НаборТестов.Добавить("Тест_ПроверитьНеАдминистраторскиеПраваНаЧтение", ПараметрыТеста, ЗаголовокТеста);

КонецЕсли;

КонецПроцедуры

И самый конечный метод, который будет тестировать объект метаданных:

Процедура Тест_ПроверитьНеАдминистраторскиеПраваНаЧтение(ОбъектМетаданных, Родитель) Экспорт

ЧтениеДоступно = Ложь;
Для Каждого ТекРоль Из Метаданные.Роли Цикл

Если ПривилегированныеРоли.Получить(ТекРоль)<>Неопределено Тогда
Продолжить;
КонецЕсли;

ПараметрыДоступаОбъекта = ПараметрыДоступа("Read", ОбъектМетаданных, , ТекРоль);
Если ПараметрыДоступаОбъекта.Доступность Тогда
ЧтениеДоступно = Истина;
Прервать;
КонецЕсли;

КонецЦикла;

Ожидаем.Что(ЧтениеДоступно).ЕстьИстина();

КонецПроцедуры

В этом методе используется переменная модуля ПривилегированныеРоли. Это Соответствие, которое заполняем ролями (Объект метаданных: Роль), обладающими расширенными полномочиями на чтение. Инициализируем и заполняем переменную также в стандартном методе Инициализация. Здесь этот код показывать особого смысла нет. См. в исходниках.

Вариант 2. Тест на проверку значений свойств РежимУправленияБлокировкойДанных

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

Код уже не так интересен, и будет расположен в спойлерах.

Опять в стандартном методе обработки тестирования проинициализируем Итератор. Но уже немного по-другому.

 

 Код:

А теперь для построения дерева тестов, воспользуемся функцией Итератор.ДеревоМетаданных().

 

 Код:

И короткий тестовый метод для фреймворка.

 

 Код:

Заключение

Итого, имеем новые знания и инструменты — разобрались, как писать плагины и дымовые тесты для фреймворков  xUnitFor1C/ADD. И написали тесты.

Исходники плагина уже можно смотреть в ADD (ветка develop), по пути add/plugins/ИтераторМетаданных/. Тесты добавятся там же (или уже добавились), в ADD, по пути add/tests/smoke/.

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

Про совместимость кода. На платформе 8.3 — будет работать в любой версии. Для запуска на платформе 8.2 нужно немного подрихтовать — закомментировать объявление областей кода (#Область/#КонецОбласти). БСП не используется.

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *