mirror of
https://github.com/bia-technologies/yaxunit.git
synced 2025-04-20 11:38:01 +02:00
238 lines
21 KiB
Markdown
238 lines
21 KiB
Markdown
---
|
|
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
|
|
ПроверкаСтрока = ЮТест.Предикат().ИмеетТип("Строка").Получить();
|
|
ПроверкаЧисло = ЮТест.Предикат().ИмеетТип("Число").Получить();
|
|
```
|
|
|
|
### Особенности реализации
|
|
|
|
Сам модуль предикатов используется только для формирования набора утверждений/условий.
|
|
|
|
За применение их в разных механизмах, реализацией проверок и формированием условий, отвечают другие модули и возможна ситуация, когда некоторые предикаты еще не реализованы или не поддерживаются каким-либо механизмом. Например, проверка заполненности не поддерживается запросами.
|