mirror of
https://github.com/bia-technologies/yaxunit.git
synced 2025-01-23 18:54:40 +02:00
259 lines
21 KiB
Markdown
259 lines
21 KiB
Markdown
|
# Мокито
|
||
|
|
||
|
Мокито - модуль созданный по образу популярного 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, Мокито.ЛюбойПараметр()))
|
||
|
.ВыполнитьМетод();
|
||
|
```
|