--- tags: [Начало, Предикаты, Утверждения, Запросы, Мокирование] sidebar_position: 4 --- # Предикаты Предикаты это довольно мощный и универсальный инструмент. С помощью предикатов вы формируете набор условий, сродни отбору. Который можно использовать: 1. В утверждениях для [проверки коллекций](assertions/assertions-base.md#проверка-на-соответствие-набору-условий-предикату) 2. В утверждениях для [проверки записей базы](assertions/assertions-db) 3. Для [получения данных базы](auxiliary-modules/queries.md) 4. Для указания условий при [обучении Мокито](mocking/mockito/mockito.md#параметры) Предикаты расширяют и унифицируют функциональность тестового движка. Механизм предикатов ([ЮТест.Предикат](/api/ЮТест#предикат)): * позволяет формировать наборы условий (отборы) и передавать их в качества параметров; * построен по модели [текучих выражений](/docs/getting-started/fluent-api.md) и имеет схожий с базовыми утверждениями синтаксис ([`ЮТест.ОжидаетЧто()`](/api/ЮТУтверждения)); * позволяет упростить и унифицировать многие механизмы движка, некоторые еще только в планах; * за счет этого, расширение функциональности предикатов автоматические расширяет функциональность многих механизмов движка. Чтобы воспользоваться предикатами, вам нужно сначала создать их с помощью конструктора [ЮТест.Предикат](/api/ЮТест#предикат), а затем передать в метод. Например, нам нужно проверить формирование записей в регистре. ```bsl Процедура АктуализацияУведомлений() Экспорт // Тест удостовериться в отсутствии нужных записей перед вызовом метода // Вызовет метод формирующий записи в регистре // Проверит наличие сформированных записей // А также проверит записи на соответствие требований ИмяРегистра = "РегистрСведений.ОповещенияПользователя"; Объект = ТестовыеДанные.Объект(); // Для этого мы формируем отбор поиска записей Отбор = ЮТест.Предикат() .Реквизит("Источник").Равно(Объект) .Реквизит("ТипОповещения").Равно(Справочники.ТипыОповещенийПользователя.Уведомление) .Получить(); // По этому отбору проверим отсутствие нужных записей ЮТест.ОжидаетЧтоТаблицаБазы(ИмяРегистра) .НеСодержитЗаписи(Отбор); УведомленияВызовСервера.АктуализацияУведомлений(); // А после вызова метода - присутствие ЮТест.ОжидаетЧтоТаблицаБазы(ИмяРегистра) .СодержитЗаписи(Отбор); // Также получим сами записи используя тот же отбор ДанныеУведомления = ЮТЗапросы.Запись(ИмяРегистра, Отбор); ЮТест.ОжидаетЧто(ДанныеУведомления) .Свойство("Прочитано").ЭтоЛожь() .Свойство("Пользователь").Равно(Справочники.ГруппыОповещенийПользователей.Инженер); КонецПроцедуры ``` ## Возможности * Проверка вложенных свойств: * [`Реквизит`](/api/ЮТПредикаты#реквизит) - Устанавливает имя реквизита, который необходимо проверить. Все последующие проверки будут относится к нему. * [`Свойство`](/api/ЮТПредикаты#свойство) - Это алиас (псевдоним) для `Реквизит` * Проверки * [`Равно`](/api/ЮТПредикаты#равно) - Добавляет предикат, проверяющий равенство объекта (свойства) указанному значению * [`НеРавно`](/api/ЮТПредикаты#неравно) - Добавляет предикат, проверяющий не равенство объекта (свойства) указанному значению * [`Заполнено`](/api/ЮТПредикаты#заполнено) - Добавляет предикат, проверяющий заполненность объекта (свойства) * [`Пусто`](/api/ЮТПредикаты#пусто) - Добавляет предикат, проверяющий, что объект (свойств) не заполнено * [`Больше`](/api/ЮТПредикаты#больше) - Добавляет предикат, проверяющий, что значение объекта (свойства) больше указанного * [`БольшеИлиРавно`](/api/ЮТПредикаты#большеилиравно) - Добавляет предикат, проверяющий, что значение объекта (свойства) больше или равно указанному * [`Меньше`](/api/ЮТПредикаты#меньше) - Добавляет предикат, проверяющий, что значение объекта (свойства) меньше указанного * [`МеньшеИлиРавно`](/api/ЮТПредикаты#меньшеилиравно) - Добавляет предикат, проверяющий, что значение объекта (свойства) меньше или равно указанному * [`ИмеетТип`](/api/ЮТПредикаты#имееттип) - Добавляет предикат, проверяющий, что значение объекта (свойства) имеет указанный тип * [`ИмеетТипОтличныйОт`](/api/ЮТПредикаты#имееттипотличныйот) - Добавляет предикат, проверяющий, что значение объекта (свойства) имеет тип отличный от указанного * [`ИмеетДлину`](/api/ЮТПредикаты#имеетдлину) - Добавляет предикат, проверяющий, длину/размер значение объекта (свойства) на равенство указанному значению * [`ИмеетДлинуОтличнуюОт`](/api/ЮТПредикаты#имеетдлинуотличнуюот) - Добавляет предикат, проверяющий, длину/размер значение объекта (свойства) на не равенство указанному значению * [`ИмеетСвойство`](/api/ЮТПредикаты#имеетсвойство) - Добавляет предикат, проверяющий, что значение объекта (реквизита) содержит вложенное свойство * [`НеИмеетСвойства`](/api/ЮТПредикаты#неимеетсвойства) - Добавляет предикат, проверяющий, что значение объекта (реквизита) не содержит вложенное свойство * [`Содержит`](/api/ЮТПредикаты#содержит) - Добавляет предикат, проверяющий, что значение объекта (реквизита) содержит указанное значение * [`НеСодержит`](/api/ЮТПредикаты#несодержит) - Добавляет предикат, проверяющий, что значение объекта (реквизита) не содержит указанное значение * [`СодержитСтрокуПоШаблону`](/api/ЮТПредикаты#содержитстрокупошаблону) - Добавляет предикат, проверяющий, что строка соответствует указанному регулярному выражению * [`НеСодержитСтрокуПоШаблону`](/api/ЮТПредикаты#несодержитстрокупошаблону) - Добавляет предикат, проверяющий, что строка не соответствует указанному регулярному выражению * [`ВСписке`](/api/ЮТПредикаты#всписке) - Добавляет условие, что проверяемое значение (или значение его свойства) входит в список значений * Между * [`Между`](/api/ЮТПредикаты#между)/[`МеждуВключаяГраницы`](/api/ЮТПредикаты#междувключаяграницы)- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал. Проверяемое значение **может** находится на границе интервала. * [`МеждуИсключаяГраницы`](/api/ЮТПредикаты#междуисключаяграницы)- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал. Проверяемое значение **не может** находится на границе интервала. * [`МеждуВключаяНачалоГраницы`](/api/ЮТПредикаты#междувключаяначалограницы)- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал. Проверяемое значение **может** находится на **начальной** границе интервала. * [`МеждуВключаяОкончаниеГраницы`](/api/ЮТПредикаты#междувключаяокончаниеграницы)- Добавляет условие, что проверяемое значение (или значение его свойства) входит в заданный интервал. Проверяемое значение **может** находится на **конечной** границе интервала. * Служебные * [`Получить`](/api/ЮТПредикаты#получить) - Возвращает набор сформированных утверждений. Рекомендуется использовать этот метод, если планируется отложенная проверка предикатов. Например, вы хотите сформировать два набору предикатов и проверять их в зависимости от условия. Метод копирует настроенный набор утверждений в массив и возвращает его, таким образом сохраняется состояние, которое можно передавать дальше. Возможно создавать предикаты на основании структуры - `ЮТест.Предикат(Структура)`, например: ```bsl // Вместо Предикат = ЮТест.Предикат() .Свойство("Наименование").Равно(НаименованиеОбъекта) .Свойство("Код").Равно(КодОбъекта); // Можно использовать структур Условия = Новый Структура("Наименование, Код", НаименованиеОбъекта, КодОбъекта); Предикат = ЮТест.Предикат(Условия); ``` ## Примеры использования * Проверка коллекции ```bsl // Проверят, что в коллекции есть элементы с реквизитом `Число`, значение которого равно `2` ЮТест.ОжидаетЧто(Коллекция) .ЛюбойЭлементСоответствуетПредикату(ЮТест.Предикат() .Реквизит("Число").Равно(2)); // Тоже самое, что и проверка выше ЮТест.ОжидаетЧто(Коллекция) .Содержит(ЮТест.Предикат() .Реквизит("Число").Равно(2)); // Проверят, что каждый элемент коллекции это заполненный массив ЮТест.ОжидаетЧто(Коллекция) .КаждыйЭлементСоответствуетПредикату(ЮТест.Предикат() .Заполнено().ИмеетТип("Массив")); // Проверят, что в коллекции нет элементов с реквизитом `Число`, значение которого равно `2` ЮТест.ОжидаетЧто(Коллекция) .НеСодержит(ЮТест.Предикат() .Реквизит("Число").Равно(2)); ``` * Описания параметров метода при мокировании Например, имеем метод, который принимает в параметрах структуру. Необходимо вернуть 2 разных результата в зависимости от значения реквизита входной структуры. ```bsl title="Проверяемый метод" Функция Посчитать(Параметры) Если Параметры.Оператор = "Сложить" Тогда Возврат Параметры.Операнд1 + Параметры.Операнд2; ИначеЕсли Параметры.Оператор = "Вычесть" Тогда Возврат Параметры.Операнд1 - Параметры.Операнд2; КонецЕсли; КонецФункции ``` ```bsl title="Тест" Мокито.Обучение(Модуль) .Когда(Модуль.Посчитать(ЮТест.Предикат() .Реквизит("Оператор").Равно("Сложить"))) .ВернутьРезультат(Результат1) .Когда(Модуль.Посчитать(ЮТест.Предикат() .Реквизит("Оператор").Равно("Вычесть"))) .ВернутьРезультат(Результат2); ``` * Утверждения, проверяющие данные в базе на основании предикатов. ```bsl ЮТест.ОжидаетЧтоТаблица("Справочник.Товары").СодержитЗаписи( ЮТест.Предикат() .Реквизит("Наименование").Равно("Товар 1") .Реквизит("Ссылка").НеРавно(Исключение) ); ``` * Получение записей из базы ```bsl ДанныеТовара = ЮТЗапросы.Запись("Справочник.Товары", ЮТест.Предикат() .Реквизит("Наименование").Равно("Товар 1") .Реквизит("Ссылка").НеРавно(Исключение)); ``` ## Особенности ### Особенности контекста Предикаты как и большинство механизмов построены на [текучих выражениях](/docs/getting-started/fluent-api.md) с сохранением состояния в глобальном [контексте](context.md). Это приводит к тому, что вы не можете сразу использовать несколько предикатов, например ```bsl Мокито.Обучение(Модуль) .Когда(Модуль.СделатьЧтоТо( ЮТест.Предикат().ИмеетТип("Строка"), ЮТест.Предикат().ИмеетТип("Число"))) .ВернутьРезультат(Результат1); ``` В этом примере 1С сначала вычислит выражения для всех параметров, а потом передаст их в метод и мы получим для обоих параметров один и тот же предикат, ожидающий тип `Число`. А все потому, что методы настройки предиката возвращают общий модуль-конструктор. Таким образом оба параметра будут иметь одно и тоже значение - общий модуль `ЮТПредикаты`, который вернет одну и туже настройку (из глобального контекста). Можно переписать настройку мокито, для большей наглядности, с использованием переменных: ```bsl Параметр1 = ЮТест.Предикат().ИмеетТип("Строка"); // Параметр1 = ОбщийМодуль.ЮТПредикаты Параметр2 = ЮТест.Предикат().ИмеетТип("Число"); // Параметр2 = ОбщийМодуль.ЮТПредикаты ЮТест.ОжидаетЧто(Параметр1).Равно(Параметр2); // Это утверждение будет успешным Мокито.Обучение(Модуль) .Когда(Модуль.СделатьЧтоТо(Параметр1, Параметр2)) .ВернутьРезультат(Результат1); ``` Для обхода этой проблемы можно использовать метод `Получить`, который возвращает текущее состояние (настройки) из конструктора и передает его в параметр метода. ```bsl Мокито.Обучение(Модуль) .Когда(Модуль.СделатьЧтоТо( ЮТест.Предикат().ИмеетТип("Строка").Получить(), ЮТест.Предикат().ИмеетТип("Число"))) .ВернутьРезультат(Результат1); ``` Такая же история при сохранение предикатов в переменные. ```bsl ПроверкаСтрока = ЮТест.Предикат().ИмеетТип("Строка"); ПроверкаЧисло = ЮТест.Предикат().ИмеетТип("Число"); ``` `ПроверкаСтрока` и `ПроверкаЧисло` будут равны и содержать одинаковые условия. Проблему также можно обойти используя метод `Получить`. ```bsl ПроверкаСтрока = ЮТест.Предикат().ИмеетТип("Строка").Получить(); ПроверкаЧисло = ЮТест.Предикат().ИмеетТип("Число").Получить(); ``` ### Особенности реализации Сам модуль предикатов используется только для формирования набора утверждений/условий. За применение их в разных механизмах, реализацией проверок и формированием условий, отвечают другие модули и возможна ситуация, когда некоторые предикаты еще не реализованы или не поддерживаются каким-либо механизмом. Например, проверка заполненности не поддерживается запросами.