1
0
mirror of https://github.com/bia-technologies/yaxunit.git synced 2025-01-23 18:54:40 +02:00
yaxunit/docs/mockito.md

259 lines
21 KiB
Markdown
Raw Normal View History

# Мокито
Мокито - модуль созданный по образу популярного java-фреймворка для тестирования [Mockito](https://site.mockito.org/). Расширяет возможности тестирования, позволяет легко менять логику работы системы подменяя результаты работы методов, отключая какие-либо алгоритмы и проверки.
Юнит-тесты, это тесты конкретных методов в отрыве от системы - контролировать данные используемые методом, изменение логики и ошибки других объектов не должны аффектить на тест.
В реальных конфигурациях объекты тесно связаны друг с другом, поэтому добиться контроля влияющих данных очень сложно. Обычно приходится создавать большой объем тестовых данных. А добиться изоляции от изменения логики других объектов почти невозможно. Мокирование же позволяет изменить логику работы системы таким образом, чтобы тестируемый метод не вызывал другие методы и использовал уже подготовленные данные. Например, для тестирования проведения реализации товаров мы можем подменить результат функции формирующей таблицу проводок и избежать сложной подготовки данных.
С помощью Мокито разработчик указывает, что делать при вызове определенных методов - вернуть нужный результат, вызвать исключение или просто не трогать ненужные методы. После тестирования разработчик может запросить и проверить статистику о вызовах, как и какие методы были вызваны.
Пример:
```bsl
ОтветСерверы = ОтветУспешногоЗапроса("Серверы");
ОтветДиски = ОтветУспешногоЗапроса("Диски");
Мокито.Обучение(РаботаСHTTP)
.Когда(РаботаСHTTP.ВыполнитьЗапрос(ПараметрыПодключения, "/hosts", "GET"))
.Вернуть(ОтветСерверы)
.Когда(РаботаСHTTP.ВыполнитьЗапрос(ПараметрыПодключения, "/disks", "GET"))
.Вернуть(ОтветДиски)
.Прогон();
Результат = БиллингДрайверГипервизорNutanix.Серверы(ПараметрыПодключения);
```
В этом примере изменяется работа модуля `РаботаСHTTP`, для функции `ВыполнитьЗапрос`, вызванной с нужными параметрами будет возвращено подготовленное значение, а сам метод не будет вызван.
Мы получим ожидаемые ответы на запросы к сторонней системе и уйдет от проблем связанных с ней - недоступность, изменение контрактов и т.д.
Работа с Мокито делится на 3 стадии:
1. Обучение - настраиваем поведение методов системы
2. Прогон - выполнение теста целевого метода
3. Проверка - анализ вызовов
## Использование
### Настройка мокируемых методов
Для работы Мокито вам необходимо добавить интересующие методы в тестовое расширение.
Эта позволит управлять поведением метода:
* подменять результат во время выполнения теста
* использовать явный вызов метода с параметрами на стадии обучения, например `Мокито.Обучение(Справочники.ИсточникиДанных).Когда(Справочники.ИсточникиДанных.СохраненныеБезопасныеДанные(Справочник)).Вернуть(Результат)`
* использовать явный вызов метода с параметрами на стадии проверки, например `Мокито.Проверить(Справочники.ИсточникиДанных).КоличествоВызовов(Справочники.ИсточникиДанных.СохраненныеБезопасныеДанные(Справочник)).Больше(1)`
Примеры добавления методов в расширение:
#### Метод общего модуля
Добавляем обработку метода `ИнициализироватьВнешнююКомпоненту` общего модуля `ОбщегоНазначенияКлиентСервер`
```bsl
&Вместо("ИнициализироватьВнешнююКомпоненту")
Функция ЮТИнициализироватьВнешнююКомпоненту(ИмяМакета, ИмяКомпоненты, ВызыватьИсключение, ПаузаЧерезКомпоненту) Экспорт
// Собираем параметры в массив
ПараметрыМетода = Мокито.МассивПараметров(ИмяМакета, ИмяКомпоненты, ВызыватьИсключение, ПаузаЧерезКомпоненту);
// Отправляем данные на анализ
ПрерватьВыполнение = Ложь;
Результат = Мокито.АнализВызова(ОбщегоНазначенияКлиентСервер, "ИнициализироватьВнешнююКомпоненту", ПараметрыМетода, ПрерватьВыполнение);
// Обрабатываем результат анализа
Если НЕ ПрерватьВыполнение Тогда
Возврат ПродолжитьВызов(ИмяМакета, ИмяКомпоненты, ВызыватьИсключение, ПаузаЧерезКомпоненту);
Иначе
Возврат Результат;
КонецЕсли;
КонецФункции
```
#### Метод модуля менеджера
Добавляем обработку метода `СохраненныеБезопасныеДанные` модуля менеджера справочника `Справочники.ИсточникиДанных`
```bsl
&Вместо("СохраненныеБезопасныеДанные")
Функция ЮТСохраненныеБезопасныеДанные(Владелец, Знач Ключи) Экспорт
// Собираем параметры в массив
ПараметрыМетода = Мокито.МассивПараметров(Владелец, Ключи);
// Отправляем данные на анализ
ПрерватьВыполнение = Ложь;
Результат = Мокито.АнализВызова(Справочники.ИсточникиДанных, "СохраненныеБезопасныеДанные", ПараметрыМетода, ПрерватьВыполнение);
// Обрабатываем результат анализа
Если НЕ ПрерватьВыполнение Тогда
Возврат ПродолжитьВызов(Владелец, Ключи);
Иначе
Возврат Результат;
КонецЕсли;
КонецФункции
```
#### Метод модуля объекта
Добавляем обработку приватного метода `ПеренестиДанныеВБезопасноеХранилище` модуля объекта справочника `Справочники.ИсточникиДанных`
```bsl
&Вместо("ПеренестиДанныеВБезопасноеХранилище")
Функция ЮТПеренестиДанныеВБезопасноеХранилище(Ключи)
// Собираем параметры в массив
ПараметрыМетода = Мокито.МассивПараметров(Ключи);
// Отправляем данные на анализ
ПрерватьВыполнение = Ложь;
Результат = Мокито.АнализВызова(ЭтотОбъект, "ПеренестиДанныеВБезопасноеХранилище", ПараметрыМетода, ПрерватьВыполнение);
// Обрабатываем результат анализа
Если НЕ ПрерватьВыполнение Тогда
Возврат ПродолжитьВызов(Ключи);
Иначе
Возврат Результат;
КонецЕсли;
КонецФункции
```
### Обучение
Самая первая стадия при написании тестов использующих моки - обучение.
Мы создаем правила как будет вести себя метод при различных вариантах вызова.
Правило состоит из условий проверки параметров и действия выполняемого при соблюдении условий.
Условия можно задать на равенство определенному значению, на проверку типа переданного значения или же безусловно принимать любый параметры
Существует 2 основных подхода к формированию условий вызова:
1. Явный вызов метода с параметрами: `Обучение(РаботаСHTTP).Когда(РаботаСHTTP.ОтправитьОбъектНаСервер(ИсточникДанных, Данные)).Вернуть(2)`
2. Указание имени метода и набора параметров: `Обучение(РаботаСHTTP).Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(ИсточникДанных, Данные)).Вернуть(2)`
Первый вариант имеет ряд недостатков:
1. Работает только для экспортных методов
2. Необходимо передавать все обязательные параметры или использовать для них маску `Мокито.ЛюбойПараметр()`
3. Если не указывать необязательные параметры, то их значения по умолчанию попадут в настройку. Покажу на примере.
Имеется метод `Функция Метод(Параметр1, Параметр2, Параметр3 = 3)`
Настройка `Когда(Метод(1, 2)).Вернуть(0)`, в результате ноль мы получим для вызовов
* `Метод(1, 2)`
* `Метод(1, 2, 3)`
Для вызова `Метод(1, 2, 4)` будет выполнен основной алгоритм метода.
А для настройки `Когда("Метод", Мокито.МассивПараметров(1, 2)).Вернуть(0)` все три варианта вызова вернут ноль.
После того как определились с условием вызова указанным в методе `Когда` нужно указать реакцию. Возможные реакции:
* `Вернуть` - вернуть указанное значение
* `ВыброситьИсключение` - вызвать исключение с переданным текстом
* `Пропустить` - пропустить выполнение метод (актуально для процедур)
#### Примеры формирования различных вариантов условий
Имеется метод:
```bsl
Функция ОтправитьОбъектНаСервер(ИсточникДанных, Объект, HTTPМетод = "POST",
ТипКонтента = "json", Преобразование = Неопределено,
ДопНастройки = Неопределено, Ответ = Неопределено, ОтветВСтруктуру = Ложь,
ТелоОтветаВХранилище = Ложь) Экспорт
```
* Переопределить все вызовы метода - указываем имя метода без указания параметров
`Мокито.Обучение(РаботаСHTTP).Когда("ОтправитьОбъектНаСервер").Вернуть(1)`
* Переопределить вызов, когда первый параметр имеет определенное значение
1. `Мокито.Обучение(РаботаСHTTP).Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(ИсточникДанных)).Вернуть(2)`
2. `Мокито.Обучение(РаботаСHTTP).Когда(РаботаСHTTP.ОтправитьОбъектНаСервер(ИсточникДанных, Мокито.ЛюбойПараметр()).Вернуть(2)`. Тут используется маска `Мокито.ЛюбойПараметр()`, тк второй параметр является обязательным
* Переопределить вызов, когда **второй** параметр имеет определенное значение
1. `Мокито.Обучение(РаботаСHTTP).Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(Мокито.ЛюбойПараметр(), Объект)).Вернуть(2)`
2. `Мокито.Обучение(РаботаСHTTP).Когда(РаботаСHTTP.ОтправитьОбъектНаСервер(Мокито.ЛюбойПараметр(), Объект).Вернуть(2)`.
* Условие на тип параметра
1. `Мокито.Обучение(РаботаСHTTP).Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(Мокито.ТипизированныйПараметр(ТипИсточникДанных), Мокито.ЧисловойПараметр())).Вернуть(3)`
2. `Мокито.Обучение(РаботаСHTTP).Когда(РаботаСHTTP.ОтправитьОбъектНаСервер(Мокито.ТипизированныйПараметр(ТипИсточникДанных), Мокито.ЧисловойПараметр()).Вернуть(3)`
## Прогон
После обучения, настройки реакций на вызовы методов, можно запускать тест нужного метода. Для перехода к этому режиму работы Мокито используется метод `Прогон`.
Все вызовы к настроенным методам (добавленным в расширение) будут перехватываться и анализироваться на совпадение условий вызова.
Для вызовов, у которых есть подходящая "реакция" будет переопределено выполнение и запустится соответствующая реакция (вернуть значение, вызвать исключение и тд), для прочих - выполнение продолжится.
```bsl
// Настройка
Мокито.Обучение(РаботаСHTTP)
.Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(Мокито.ЛюбойПараметр(), Мокито.ЛюбойПараметр()))
.Вернуть(РезультатПоУмолчанию)
.Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(Справочники.ИсточникиДанных.FTP, 2))
.Вернуть(2)
.Прогон(); // Перевод в режим прогона теста
Результат = РаботаСHTTP.ОтправитьОбъектНаСервер(ИсточникДанных, Данные); // Результат будет равен переменной РезультатПоУмолчанию
Результат = РаботаСHTTP.ОтправитьОбъектНаСервер(Справочники.ИсточникиДанных.FTP, 2); // Результат будет равен 2
```
## Проверка
После прогона теста можно проверить какие методы, с какими параметрами вызывались. Для этих целей необходимо воспользоваться методом `Проверить`
```bsl
Мокито.Проверить(РаботаСHTTP) // Устанавливаем проверяемый объект
.КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(ЛюбойПараметр, Мокито.ЧисловойПараметр())) // Условия поиска вызовов
.Больше(1) // Проверки
.Равно(2)
.КоличествоВызовов("ОтправитьОбъектНаСервер").Заполнено().Равно(3).Меньше(6)
.КоличествоВызовов("ОтправитьЗапросHTTP").Пусто().Меньше(1)
.КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(1, 2)).Равно(1)
.КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(ЛюбойПараметр, ЛюбойПараметр)).Равно(3)
.КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(Мокито.ТипизированныйПараметр(ТипИсточникДанных), ЛюбойПараметр)).Равно(1)
```
Принцип формирования проверки:
* Указываем проверяемый объект `Проверить(РаботаСHTTP)`.
* Указываем условия поиска вызовов метода. Логика формирования условия такая же как при обучении.
Например, `КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(ЛюбойПараметр, Мокито.ЧисловойПараметр()))`
Соберет все вызовы метода `РаботаСHTTP.ОтправитьОбъектНаСервер`, к которых вторым параметром идет число, а 3й и последующий параметры имеют значения по умолчанию.
* Проверяем собранные вызовы:
* `Заполнено` - есть вызовы метода по указанным условиям
* `Пусто` - нет вызовов метода по указанным условиям
* `Равно` - количество вызовов попавших под условия равно указанному значению
* `Больше` - количество вызовов попавших под условия больше указанного значения
* `Меньше` - количество вызовов попавших под условия меньше указанного значения
## Кейсы использования\*
\* *В примерах опускается часть добавления метода в расширение*
1. Подмена результат функции для любого вызова
```bsl
Мокито.Обучение(РаботаСHTTP)
.Когда("ОтправитьОбъектНаСервер")
.Вернуть(1)
```
2. Выключение алгоритма проведения документа
```bsl
Мокито.Обучение(СсылкаИлиОбъектДокумент)
.Когда("ОбработкаПроведения")
.Пропустить()
```
3. Выбросить исключение, если в метод передан некорректный набор параметров
```bsl
Мокито.Обучение(РаботаСHTTP)
.Когда("ОтправитьОбъектНаСервер")
.ВыброситьИсключение("Не верные параметры вызова")
.Когда(РаботаСHTTP.ОтправитьОбъектНаСервер(Справочники.ИсточникиДанных.FTP, Мокито.ЛюбойПараметр()))
.ВыполнитьМетод();
```