1
0
mirror of https://github.com/bia-technologies/yaxunit.git synced 2025-01-08 13:06:32 +02:00
yaxunit/documentation/docs/user-api/mockito.md
2023-02-14 23:14:39 +03:00

22 KiB

tags
Getting started
Mock

Мокито

Мокито - модуль созданный по образу популярного java-фреймворка для тестирования Mockito. Расширяет возможности тестирования, позволяет легко менять логику работы системы подменяя результаты работы методов, отключая какие-либо алгоритмы и проверки.

Юнит-тесты, это тесты конкретных методов в отрыве от системы - контролировать данные используемые методом, изменение логики и ошибки других объектов не должны аффектить на тест. В реальных конфигурациях объекты тесно связаны друг с другом, поэтому добиться контроля влияющих данных очень сложно. Обычно приходится создавать большой объем тестовых данных. А добиться изоляции от изменения логики других объектов почти невозможно. Мокирование же позволяет изменить логику работы системы таким образом, чтобы тестируемый метод не вызывал другие методы и использовал уже подготовленные данные. Например, для тестирования проведения реализации товаров мы можем подменить результат функции формирующей таблицу проводок и избежать сложной подготовки данных.

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

Пример:

ОтветСерверы = ОтветУспешногоЗапроса("Серверы");
ОтветДиски = ОтветУспешногоЗапроса("Диски");

Мокито.Обучение(РаботаСHTTP)
    .Когда(РаботаСHTTP.ВыполнитьЗапрос(ПараметрыПодключения, "/hosts", "GET"))
    .Вернуть(ОтветСерверы)
    .Когда(РаботаСHTTP.ВыполнитьЗапрос(ПараметрыПодключения, "/disks", "GET"))
    .Вернуть(ОтветДиски)
    .Прогон();

Результат = БиллингДрайверГипервизорNutanix.Серверы(ПараметрыПодключения);

В этом примере изменяется работа модуля РаботаСHTTP, для функции ВыполнитьЗапрос, вызванной с нужными параметрами будет возвращено подготовленное значение, а сам метод не будет вызван. Мы получим ожидаемые ответы на запросы к сторонней системе и уйдет от проблем связанных с ней - недоступность, изменение контрактов и т.д.

Работа с Мокито делится на 3 стадии:

flowchart LR
    training(Обучение) --> run(Прогон, запуск тестового метода)
    run --> check(Проверка)

Использование

Настройка мокируемых методов

Для работы Мокито вам необходимо добавить интересующие методы в тестовое расширение.

Эта позволит управлять поведением метода:

  • подменять результат во время выполнения теста
  • использовать явный вызов метода с параметрами на стадии обучения, например Мокито.Обучение(Справочники.ИсточникиДанных).Когда(Справочники.ИсточникиДанных.СохраненныеБезопасныеДанные(Справочник)).Вернуть(Результат)
  • использовать явный вызов метода с параметрами на стадии проверки, например Мокито.Проверить(Справочники.ИсточникиДанных).КоличествоВызовов(Справочники.ИсточникиДанных.СохраненныеБезопасныеДанные(Справочник)).Больше(1)

Примеры добавления методов в расширение.

Метод общего модуля

Добавляем обработку метода ИнициализироватьВнешнююКомпоненту общего модуля ОбщегоНазначенияКлиентСервер

&Вместо("ИнициализироватьВнешнююКомпоненту")
Функция ЮТИнициализироватьВнешнююКомпоненту(ИмяМакета, ИмяКомпоненты, ВызыватьИсключение, ПаузаЧерезКомпоненту) Экспорт
    // Собираем параметры в массив
    ПараметрыМетода = Мокито.МассивПараметров(ИмяМакета, ИмяКомпоненты, ВызыватьИсключение, ПаузаЧерезКомпоненту);

    // Отправляем данные на анализ
    ПрерватьВыполнение = Ложь;
    Результат = Мокито.АнализВызова(ОбщегоНазначенияКлиентСервер, "ИнициализироватьВнешнююКомпоненту", ПараметрыМетода, ПрерватьВыполнение);

    // Обрабатываем результат анализа
    Если НЕ ПрерватьВыполнение Тогда
        Возврат ПродолжитьВызов(ИмяМакета, ИмяКомпоненты, ВызыватьИсключение, ПаузаЧерезКомпоненту);
    Иначе
        Возврат Результат;
    КонецЕсли;
КонецФункции

Метод модуля менеджера

Добавляем обработку метода СохраненныеБезопасныеДанные модуля менеджера справочника Справочники.ИсточникиДанных

&Вместо("СохраненныеБезопасныеДанные")
Функция ЮТСохраненныеБезопасныеДанные(Владелец, Знач Ключи) Экспорт

    // Собираем параметры в массив
    ПараметрыМетода = Мокито.МассивПараметров(Владелец, Ключи);

    // Отправляем данные на анализ
    ПрерватьВыполнение = Ложь;
    Результат = Мокито.АнализВызова(Справочники.ИсточникиДанных, "СохраненныеБезопасныеДанные", ПараметрыМетода, ПрерватьВыполнение);

    // Обрабатываем результат анализа
    Если НЕ ПрерватьВыполнение Тогда
        Возврат ПродолжитьВызов(Владелец, Ключи);
    Иначе
        Возврат Результат;
    КонецЕсли;

КонецФункции

Метод модуля объекта

Добавляем обработку приватного метода ПеренестиДанныеВБезопасноеХранилище модуля объекта справочника Справочники.ИсточникиДанных

&Вместо("ПеренестиДанныеВБезопасноеХранилище")
Функция ЮТПеренестиДанныеВБезопасноеХранилище(Ключи)

    // Собираем параметры в массив
    ПараметрыМетода = Мокито.МассивПараметров(Ключи);

    // Отправляем данные на анализ
    ПрерватьВыполнение = Ложь;
    Результат = Мокито.АнализВызова(ЭтотОбъект, "ПеренестиДанныеВБезопасноеХранилище", ПараметрыМетода, ПрерватьВыполнение);

    // Обрабатываем результат анализа
    Если НЕ ПрерватьВыполнение Тогда
        Возврат ПродолжитьВызов(Ключи);
    Иначе
        Возврат Результат;
    КонецЕсли;

КонецФункции

Обучение

Самая первая стадия при написании тестов использующих моки - обучение. Мы создаем правила как будет вести себя метод при различных вариантах вызова. Правило состоит из условий проверки параметров и действия выполняемого при соблюдении условий.

Условия можно задать на равенство определенному значению, на проверку типа переданного значения или же безусловно принимать любый параметры

Существует 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) все три варианта вызова вернут ноль.

После того как определились с условием вызова указанным в методе Когда нужно указать реакцию. Возможные реакции:

  • Вернуть - вернуть указанное значение
  • ВыброситьИсключение - вызвать исключение с переданным текстом
  • Пропустить - пропустить выполнение метод (актуально для процедур)

Примеры формирования различных вариантов условий

Имеется метод:

Функция ОтправитьОбъектНаСервер(ИсточникДанных, Объект, 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)

Прогон

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

Все вызовы к настроенным методам (добавленным в расширение) будут перехватываться и анализироваться на совпадение условий вызова. Для вызовов, у которых есть подходящая "реакция" будет переопределено выполнение и запустится соответствующая реакция (вернуть значение, вызвать исключение и тд), для прочих - выполнение продолжится.

// Настройка
Мокито.Обучение(РаботаСHTTP)
    .Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(Мокито.ЛюбойПараметр(), Мокито.ЛюбойПараметр()))
    .Вернуть(РезультатПоУмолчанию)
    .Когда("ОтправитьОбъектНаСервер", Мокито.МассивПараметров(Справочники.ИсточникиДанных.FTP, 2))
    .Вернуть(2)
    .Прогон(); // Перевод в режим прогона теста

Результат = РаботаСHTTP.ОтправитьОбъектНаСервер(ИсточникДанных, Данные); // Результат будет равен переменной РезультатПоУмолчанию
Результат = РаботаСHTTP.ОтправитьОбъектНаСервер(Справочники.ИсточникиДанных.FTP, 2); // Результат будет равен 2

Проверка

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

Мокито.Проверить(РаботаСHTTP) // Устанавливаем проверяемый объект
    .КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(ЛюбойПараметр, Мокито.ЧисловойПараметр())) // Условия поиска вызовов
    .Больше(1) // Проверки
    .Равно(2)
    .КоличествоВызовов("ОтправитьОбъектНаСервер").Заполнено().Равно(3).Меньше(6)
    .КоличествоВызовов("ОтправитьЗапросHTTP").Пусто().Меньше(1)
    .КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(1, 2)).Равно(1)
    .КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(ЛюбойПараметр, ЛюбойПараметр)).Равно(3)
    .КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(Мокито.ТипизированныйПараметр(ТипИсточникДанных), ЛюбойПараметр)).Равно(1)

Принцип формирования проверки:

  • Указываем проверяемый объект Проверить(РаботаСHTTP).
  • Указываем условия поиска вызовов метода. Логика формирования условия такая же как при обучении. Например, КоличествоВызовов(РаботаСHTTP.ОтправитьОбъектНаСервер(ЛюбойПараметр, Мокито.ЧисловойПараметр())) Соберет все вызовы метода РаботаСHTTP.ОтправитьОбъектНаСервер, к которых вторым параметром идет число, а 3й и последующий параметры имеют значения по умолчанию.
  • Проверяем собранные вызовы:
    • Заполнено - есть вызовы метода по указанным условиям
    • Пусто - нет вызовов метода по указанным условиям
    • Равно - количество вызовов попавших под условия равно указанному значению
    • Больше - количество вызовов попавших под условия больше указанного значения
    • Меньше - количество вызовов попавших под условия меньше указанного значения

Кейсы использования*

* В примерах опускается часть добавления метода в расширение

  1. Подмена результат функции для любого вызова

    Мокито.Обучение(РаботаСHTTP)
        .Когда("ОтправитьОбъектНаСервер")
        .Вернуть(1)
    
  2. Выключение алгоритма проведения документа

    Мокито.Обучение(СсылкаИлиОбъектДокумент)
        .Когда("ОбработкаПроведения")
        .Пропустить()
    
  3. Выбросить исключение, если в метод передан некорректный набор параметров

    Мокито.Обучение(РаботаСHTTP)
        .Когда("ОтправитьОбъектНаСервер")
        .ВыброситьИсключение("Не верные параметры вызова")
        .Когда(РаботаСHTTP.ОтправитьОбъектНаСервер(Справочники.ИсточникиДанных.FTP, Мокито.ЛюбойПараметр()))
        .ВыполнитьМетод();