Skip to content
Библиотека для создания моков и стабов в стиле mockito
1C Enterprise
Branch: develop
Clone or download
Pull request Compare This branch is 11 commits behind nixel2007:develop.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode
tasks
tests
Классы
Модули
.gitignore
.travis.yml
CHANGELOG.md
LICENSE
README.md
packagedef
test.os

README.md

Moskito - mock this script!

Build Status

Библиотека предназначена для создания моков (mock) и стабов (stub) в OneScript. За основу взят фреймворк mockito для Java.

Цели создания библиотеки

Периодически в тестировании возникают задачи проверки работы модулей или классов, имеющих внешние зависимости. Этими зависимостями могут быть как безобидные вспомогательные классы (например, библиотеки cmdline, logos), так и зависимости, требующие определенного "внешнего" состояния. Например, Файл или HTTPСоединение.

Для возможности эмуляции работы таких классов и была создана эта библиотека.

Примеры использования

Эмуляция работы http-соединения

HTTPЗапрос = Новый HTTPЗапрос("/ping");

МокСоединение = Мок.Получить(Новый HTTPСоединение("localhost"));

// Вызов метода Получить по умолчанию вернет NULL, без исключений о недоступности сервиса
Результат = МокСоединение.Получить(HTTPЗапрос);
Ожидаем.Что(Результат).Равно(NULL);

// Но можно вызвать исключение
МокСоединение.Когда().Получить(HTTPЗапрос).ТогдаВыбрасываетИсключение(Новый ИнформацияОбОшибке("Ресурс недоступен", Новый Структура));
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(HTTPЗапрос);
Ожидаем.Что(МокСоединение).Метод("Получить", МассивПараметров).ВыбрасываетИсключение("Ресурс недоступен");

// Начальные свойства мокируемого объекта переносятся в сам мок
Ожидаем.Что(МокСоединение.Сервер).Равно("localhost");

// Можно переопределить результат работы метода
МокСоединение.Когда().Получить(HTTPЗапрос).ТогдаВозвращает("Переопределенный ответ");
Результат = МокСоединение.Получить(HTTPЗапрос);
Ожидаем.Что(Результат).Равно("Переопределенный ответ");

// Некоторые объекты нельзя создавать через конструктор.
// Для таких объектов можно воспользоваться созданием мока из типа.
Ответ = Мок.Получить(Тип("HTTPОтвет"));
Ответ.КодСостояния = 200;
Ответ.Когда().ПолучитьТелоКакСтроку().ТогдаВозвращает("Переопределенный ответ");

// Моки можно вкладывать в моки
МокСоединение.Когда().Получить(HTTPЗапрос).ТогдаВозвращает(Ответ);
Результат = МокСоединение.Получить(HTTPЗапрос);
Ожидаем.Что(Результат.ПолучитьТелоКакСтроку()).Равно("Переопределенный ответ");

// При этом вызов метода с другими параметрами продолжит возвращать NULL
Результат = МокСоединение.Получить("/test");
Ожидаем.Что(Результат).Равно(NULL);

Использование матчеров

Для переопределения результатов методов не обязательно передавать точные значения параметров. Можно использовать "матчеры". Матчер - это специальная функция, которая проверяет, что параметр удовлетворяет какому-то условию.

МокОбъект = Мок.Получить(Тип("Структура"));

// Заставим структуру для проверки всех свойств возвращать "Истина"
МокОбъект.Когда().Свойство(Матчеры.ЛюбаяСтрока()).ТогдаВозвращает(Истина);

// Теперь любой вызов метода "Свойства" с переданной строкой будет возвращать "Истина"
Ожидаем.Что(МокОбъект.Свойство("Строка")).Равно(Истина);
Ожидаем.Что(МокОбъект.Свойство("ДругаяСтрока")).Равно(Истина);

// Вызов функции, например, с числом, продолжит возвращать NULL
Ожидаем.Что(МокОбъект.Свойство("ДругаяСтрока")).Равно(NULL);

Матчер - это функция, которая должна вернуть Истина или Ложь. Вы можете написать матчер любой сложности, используся специальный конструктор.

// Функция-матчер принимает минимум один параметр
//  Значение - Произвольный - само проверяемое значение
// 
// В функции могут содержаться дополнительные параметры. Значения таких параметров должны передаваться
// в виде массива при создании матчера.
//
Функция БольшеТрех(Знач Значение) Экспорт
    Возврат Значение > 3;
КонецФункции

МокОбъект = Мок.Получить(Тип("Структура"));

СвойМатчер = Новый Матчер(ЭтотОбъект, "БольшеТрех");
МокОбъект.Когда().Свойство(СвойМатчер).ТогдаВозвращает(Истина);

Ожидаем.Что(МокОбъект.Свойство(0)).Равно(NULL);
Ожидаем.Что(МокОбъект.Свойство(3)).Равно(NULL);
Ожидаем.Что(МокОбъект.Свойство(4)).Равно(Истина);

Переопределение с использованием Ответов

В сложных тестовых случаях методов ТогдаВозвращает и ТогдаВыбрасываетИсключение может не хватать. Вы можете реализовать более сложную логику ответа с использованием метода ТогдаОтвечает

// Допустим у нас есть функция, которая просто возвращает строковую информацию
// о вызванном методе.
 
Функция ВернутьИнформациюОВызове(Знач ИнформацияОВызове) Экспорт

    // Параметр ИнформацияОВызове хранит данные о самом моке, вызываемом методе,
    // и массиве параметров, с которым вызвали этот метод.
	МокОбъект = ИнформацияОВызове.Мок();
	ИмяМетода = ИнформацияОВызове.ИмяМетода();
	Параметры = ИнформацияОВызове.Параметры();

    // Преобразование массива в строку.
	Параметры = ПроцессорыКоллекций.ИзКоллекции(Параметры).ВСтроку(", ");

    // Произовльное возвращаемое значение
	Возврат СтрШаблон("Вызван метод <%1> с параметрами <%2>", ИмяМетода, Параметры);
 
КонецФункции

// Создадим указатель на функцию, которая должна вызываться при "ответе"
Ответ = Новый Ответ(ЭтотОбъект, "ВернутьИнформациюОВызове");

МокОбъект = Мок.Получить(Тип("Структура"));
// Когда у мока вызывается метод Свойство(), срабатывает вызов функции, заложенной в "Ответе" 
МокОбъект.Когда().Свойство(Матчеры.ЛюбаяСтрока(), Матчеры.ЛюбоеЗначение()).ТогдаОтвечает(Ответ);

// Вызовем функцию
Результат = МокОбъект.Свойство("Поле");

// В "Результате" получим строку, возвращенную функцией ВернутьИнформациюОВызове
Ожидаем.Что(Результат).Равно("Вызван метод <Свойство> с параметрами <Поле, >");

Проверка вызова методов

// Допустим у нас есть класс, принимающий в себя HTTPСоединение, и вызывающий у него метод Получить()
// Проверим, что метод Получить() действительно вызывался

МойКласс = Новый МойКласс();
МокСоединение = Мок.Получить(Новый HTTPСоединение("localhost"));

МойКласс.УстановитьКонтекст(МокСоединение);
МойКласс.ВызватьМетодКоторыйДолженДернутьПолучить("/ping");

// Если метод Получить не вызывался, будет выдано исключение
МокСоединение.ПроверитьЧтоВызывалсяМетод().Получить("/ping");

Режим "шпиона" (spy)

// Создаем нового шпиона над Структурой
МокСтруктура = Мок.Следить(Новый Структура);

// Шпион вызывает реальные методы объекта
МокСтруктура.Вставить("Ключ1", 1);

// Методы "внутреннего" объекта работают как обычно
Ожидаем.Что(МокСтруктура.Количество()).Равно(1);

МокСтруктура.Вставить("Ключ2", 2);

// Однако, мы можем все еще можем переопределить (stub) результат работы любого метода
МокСтруктура.Когда().Количество().ТогдаВозвращает(999);

// В этом случае будет возвращаться наше значение.
Ожидаем.Что(МокСтруктура.Количество()).Равно(999);

Имеющиеся ограничения

  • В силу ограничений движка на создание методов с именами, совпадающими с именами глобальных методов, не от всех объектов можно создать идентичный мок. Например, если создать мок от Массив, то метод Найти(), совпадающий по имени с глобальным методом, будет переименован в метод _Найти(). Структура же замокается без проблем.
You can’t perform that action at this time.