Перейти к основному содержимому

Предикаты

Предикаты это довольно мощный и универсальный инструмент. С помощью предикатов вы формируете набор условий, сродни отбору. Который можно использовать:

  1. В утверждениях для проверки коллекций
  2. В утверждениях для проверки записей базы
  3. Для получения данных базы
  4. Для указания условий при обучении Мокито

Предикаты расширяют и унифицируют функциональность тестового движка.

Механизм предикатов (ЮТест.Предикат):

  • позволяет формировать наборы условий (отборы) и передавать их в качества параметров;
  • построен по модели текучих выражений и имеет схожий с базовыми утверждениями синтаксис (ЮТест.ОжидаетЧто());
  • позволяет упростить и унифицировать многие механизмы движка, некоторые еще только в планах;
  • за счет этого, расширение функциональности предикатов автоматические расширяет функциональность многих механизмов движка.

Чтобы воспользоваться предикатами, вам нужно сначала создать их с помощью конструктора ЮТест.Предикат, а затем передать в метод.

Например, нам нужно проверить формирование записей в регистре.

Процедура АктуализацияУведомлений() Экспорт

// Тест удостовериться в отсутствии нужных записей перед вызовом метода
// Вызовет метод формирующий записи в регистре
// Проверит наличие сформированных записей
// А также проверит записи на соответствие требований

ИмяРегистра = "РегистрСведений.ОповещенияПользователя";
Объект = ТестовыеДанные.Объект();

// Для этого мы формируем отбор поиска записей
Отбор = ЮТест.Предикат()
.Реквизит("Источник").Равно(Объект)
.Реквизит("ТипОповещения").Равно(Справочники.ТипыОповещенийПользователя.Уведомление)
.Получить();

// По этому отбору проверим отсутствие нужных записей
ЮТест.ОжидаетЧтоТаблицаБазы(ИмяРегистра)
.НеСодержитЗаписи(Отбор);

УведомленияВызовСервера.АктуализацияУведомлений();

// А после вызова метода - присутствие
ЮТест.ОжидаетЧтоТаблицаБазы(ИмяРегистра)
.СодержитЗаписи(Отбор);

// Также получим сами записи используя тот же отбор
ДанныеУведомления = ЮТЗапросы.Запись(ИмяРегистра, Отбор);

ЮТест.ОжидаетЧто(ДанныеУведомления)
.Свойство("Прочитано").ЭтоЛожь()
.Свойство("Пользователь").Равно(Справочники.ГруппыОповещенийПользователей.Инженер);

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

Возможности

  • Проверка вложенных свойств:
    • Реквизит - Устанавливает имя реквизита, который необходимо проверить. Все последующие проверки будут относится к нему.
    • Свойство - Это алиас (псевдоним) для Реквизит
  • Проверки
    • Равно - Добавляет предикат, проверяющий равенство объекта (свойства) указанному значению
    • НеРавно - Добавляет предикат, проверяющий не равенство объекта (свойства) указанному значению
    • Заполнено - Добавляет предикат, проверяющий заполненность объекта (свойства)
    • Пусто - Добавляет предикат, проверяющий, что объект (свойств) не заполнено
    • Больше - Добавляет предикат, проверяющий, что значение объекта (свойства) больше указанного
    • БольшеИлиРавно - Добавляет предикат, проверяющий, что значение объекта (свойства) больше или равно указанному
    • Меньше - Добавляет предикат, проверяющий, что значение объекта (свойства) меньше указанного
    • МеньшеИлиРавно - Добавляет предикат, проверяющий, что значение объекта (свойства) меньше или равно указанному
    • ИмеетТип - Добавляет предикат, проверяющий, что значение объекта (свойства) имеет указанный тип
    • ИмеетТипОтличныйОт - Добавляет предикат, проверяющий, что значение объекта (свойства) имеет тип отличный от указанного
    • ИмеетДлину - Добавляет предикат, проверяющий, длину/размер значение объекта (свойства) на равенство указанному значению
    • ИмеетДлинуОтличнуюОт - Добавляет предикат, проверяющий, длину/размер значение объекта (свойства) на не равенство указанному значению
    • ИмеетСвойство - Добавляет предикат, проверяющий, что значение объекта (реквизита) содержит вложенное свойство
    • НеИмеетСвойства - Добавляет предикат, проверяющий, что значение объекта (реквизита) не содержит вложенное свойство
    • Содержит - Добавляет предикат, проверяющий, что значение объекта (реквизита) содержит указанное значение
    • НеСодержит - Добавляет предикат, проверяющий, что значение объекта (реквизита) не содержит указанное значение
    • СодержитСтрокуПоШаблону - Добавляет предикат, проверяющий, что строка соответствует указанному регулярному выражению
    • НеСодержитСтрокуПоШаблону - Добавляет предикат, проверяющий, что строка не соответствует указанному регулярному выражению
    • ВСписке - Добавляет условие, что проверяемое значение (или значение его свойства) входит в список значений
    • Между
      • Между/МеждуВключаяГраницы- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал.
        Проверяемое значение может находится на границе интервала.
      • МеждуИсключаяГраницы- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал.
        Проверяемое значение не может находится на границе интервала.
      • МеждуВключаяНачалоГраницы- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал.
        Проверяемое значение может находится на начальной границе интервала.
      • МеждуВключаяОкончаниеГраницы- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал.
        Проверяемое значение может находится на конечной границе интервала.
  • Служебные
    • Получить - Возвращает набор сформированных утверждений.
      Рекомендуется использовать этот метод, если планируется отложенная проверка предикатов. Например, вы хотите сформировать два набору предикатов и проверять их в зависимости от условия.
      Метод копирует настроенный набор утверждений в массив и возвращает его, таким образом сохраняется состояние, которое можно передавать дальше.

Возможно создавать предикаты на основании структуры - ЮТест.Предикат(Структура), например:

// Вместо
Предикат = ЮТест.Предикат()
.Свойство("Наименование").Равно(НаименованиеОбъекта)
.Свойство("Код").Равно(КодОбъекта);

// Можно использовать структур
Условия = Новый Структура("Наименование, Код", НаименованиеОбъекта, КодОбъекта);
Предикат = ЮТест.Предикат(Условия);

Примеры использования

  • Проверка коллекции
    // Проверят, что в коллекции есть элементы с реквизитом `Число`, значение которого равно `2`
    ЮТест.ОжидаетЧто(Коллекция)
    .ЛюбойЭлементСоответствуетПредикату(ЮТест.Предикат()
    .Реквизит("Число").Равно(2));

    // Тоже самое, что и проверка выше
    ЮТест.ОжидаетЧто(Коллекция)
    .Содержит(ЮТест.Предикат()
    .Реквизит("Число").Равно(2));

    // Проверят, что каждый элемент коллекции это заполненный массив
    ЮТест.ОжидаетЧто(Коллекция)
    .КаждыйЭлементСоответствуетПредикату(ЮТест.Предикат()
    .Заполнено().ИмеетТип("Массив"));

    // Проверят, что в коллекции нет элементов с реквизитом `Число`, значение которого равно `2`
    ЮТест.ОжидаетЧто(Коллекция)
    .НеСодержит(ЮТест.Предикат()
    .Реквизит("Число").Равно(2));
  • Описания параметров метода при мокировании
    Например, имеем метод, который принимает в параметрах структуру. Необходимо вернуть 2 разных результата в зависимости от значения реквизита входной структуры.
    Проверяемый метод
    Функция Посчитать(Параметры)
    Если Параметры.Оператор = "Сложить" Тогда
    Возврат Параметры.Операнд1 + Параметры.Операнд2;
    ИначеЕсли Параметры.Оператор = "Вычесть" Тогда
    Возврат Параметры.Операнд1 - Параметры.Операнд2;
    КонецЕсли;
    КонецФункции
    Тест
    Мокито.Обучение(Модуль)
    .Когда(Модуль.Посчитать(ЮТест.Предикат()
    .Реквизит("Оператор").Равно("Сложить")))
    .ВернутьРезультат(Результат1)

    .Когда(Модуль.Посчитать(ЮТест.Предикат()
    .Реквизит("Оператор").Равно("Вычесть")))
    .ВернутьРезультат(Результат2);
  • Утверждения, проверяющие данные в базе на основании предикатов.
    ЮТест.ОжидаетЧтоТаблица("Справочник.Товары").СодержитЗаписи(
    ЮТест.Предикат()
    .Реквизит("Наименование").Равно("Товар 1")
    .Реквизит("Ссылка").НеРавно(Исключение)
    );
  • Получение записей из базы
    ДанныеТовара = ЮТЗапросы.Запись("Справочник.Товары", ЮТест.Предикат()
    .Реквизит("Наименование").Равно("Товар 1")
    .Реквизит("Ссылка").НеРавно(Исключение));

Особенности

Особенности контекста

Предикаты как и большинство механизмов построены на текучих выражениях с сохранением состояния в глобальном контексте.

Это приводит к тому, что вы не можете сразу использовать несколько предикатов, например

Мокито.Обучение(Модуль)
.Когда(Модуль.СделатьЧтоТо(
ЮТест.Предикат().ИмеетТип("Строка"),
ЮТест.Предикат().ИмеетТип("Число")))
.ВернутьРезультат(Результат1);

В этом примере 1С сначала вычислит выражения для всех параметров, а потом передаст их в метод и мы получим для обоих параметров один и тот же предикат, ожидающий тип Число.

А все потому, что методы настройки предиката возвращают общий модуль-конструктор. Таким образом оба параметра будут иметь одно и тоже значение - общий модуль ЮТПредикаты, который вернет одну и туже настройку (из глобального контекста).
Можно переписать настройку мокито, для большей наглядности, с использованием переменных:

Параметр1 = ЮТест.Предикат().ИмеетТип("Строка"); // Параметр1 = ОбщийМодуль.ЮТПредикаты
Параметр2 = ЮТест.Предикат().ИмеетТип("Число"); // Параметр2 = ОбщийМодуль.ЮТПредикаты

ЮТест.ОжидаетЧто(Параметр1).Равно(Параметр2); // Это утверждение будет успешным

Мокито.Обучение(Модуль)
.Когда(Модуль.СделатьЧтоТо(Параметр1, Параметр2))
.ВернутьРезультат(Результат1);

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

Мокито.Обучение(Модуль)
.Когда(Модуль.СделатьЧтоТо(
ЮТест.Предикат().ИмеетТип("Строка").Получить(),
ЮТест.Предикат().ИмеетТип("Число")))
.ВернутьРезультат(Результат1);

Такая же история при сохранение предикатов в переменные.

ПроверкаСтрока = ЮТест.Предикат().ИмеетТип("Строка");
ПроверкаЧисло = ЮТест.Предикат().ИмеетТип("Число");

ПроверкаСтрока и ПроверкаЧисло будут равны и содержать одинаковые условия. Проблему также можно обойти используя метод Получить.

ПроверкаСтрока = ЮТест.Предикат().ИмеетТип("Строка").Получить();
ПроверкаЧисло = ЮТест.Предикат().ИмеетТип("Число").Получить();

Особенности реализации

Сам модуль предикатов используется только для формирования набора утверждений/условий.

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