https://github.com/nixel2007/moskito
Библиотека для создания моков и стабов в стиле mockito
https://github.com/nixel2007/moskito
oscript-lib oscript-package
Last synced: 4 months ago
JSON representation
Библиотека для создания моков и стабов в стиле mockito
- Host: GitHub
- URL: https://github.com/nixel2007/moskito
- Owner: nixel2007
- License: mit
- Created: 2017-10-13T11:34:50.000Z (over 8 years ago)
- Default Branch: develop
- Last Pushed: 2021-02-19T21:33:34.000Z (almost 5 years ago)
- Last Synced: 2025-10-10T11:31:56.415Z (4 months ago)
- Topics: oscript-lib, oscript-package
- Language: 1C Enterprise
- Size: 142 KB
- Stars: 7
- Watchers: 4
- Forks: 8
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Moskito - mock this script!
[](https://github.com/nixel2007/moskito/actions/workflows/main.yml)
[](https://sonar.openbsl.ru/dashboard?id=moskito)
[](https://sonar.openbsl.ru/dashboard?id=moskito)
Библиотека предназначена для создания моков (mock) и стабов (stub) в OneScript. За основу взят фреймворк [mockito](http://site.mockito.org/) для Java.
## Цели создания библиотеки
Периодически в тестировании возникают задачи проверки работы модулей или классов, имеющих внешние зависимости. Этими зависимостями могут быть как безобидные вспомогательные классы (например, библиотеки `cmdline`, `logos`), так и зависимости, требующие определенного "внешнего" состояния. Например, `Файл` или `HTTPСоединение`.
Для возможности эмуляции работы таких классов и была создана эта библиотека.
## Примеры использования
### Эмуляция работы http-соединения
```bsl
HTTPЗапрос = Новый HTTPЗапрос("/ping");
МокСоединение = Мок.Получить(Новый HTTPСоединение("localhost"));
// Вызов метода Получить по умолчанию вернет NULL, без исключений о недоступности сервиса
Результат = МокСоединение.Получить(HTTPЗапрос);
Ожидаем.Что(Результат).Равно(NULL);
// Но можно вызвать исключение
МокСоединение.Когда().Получить(HTTPЗапрос).ТогдаВыбрасываетИсключение(Новый ИнформацияОбОшибке("Ресурс недоступен", Новый Структура));
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(HTTPЗапрос);
Ожидаем.Что(МокСоединение).Метод("Получить", МассивПараметров).ВыбрасываетИсключение("Ресурс недоступен");
// Начальные свойства мокируемого объекта переносятся в сам мок
Ожидаем.Что(МокСоединение.Сервер).Равно("localhost");
// Можно переопределить результат работы метода
МокСоединение.Когда().Получить(HTTPЗапрос).ТогдаВозвращает("Переопределенный ответ");
Результат = МокСоединение.Получить(HTTPЗапрос);
Ожидаем.Что(Результат).Равно("Переопределенный ответ");
// Некоторые объекты нельзя создавать через конструктор.
// Для таких объектов можно воспользоваться созданием мока из типа.
Ответ = Мок.Получить(Тип("HTTPОтвет"));
Ответ.КодСостояния = 200;
Ответ.Когда().ПолучитьТелоКакСтроку().ТогдаВозвращает("Переопределенный ответ");
// Моки можно вкладывать в моки
МокСоединение.Когда().Получить(HTTPЗапрос).ТогдаВозвращает(Ответ);
Результат = МокСоединение.Получить(HTTPЗапрос);
Ожидаем.Что(Результат.ПолучитьТелоКакСтроку()).Равно("Переопределенный ответ");
// При этом вызов метода с другими параметрами продолжит возвращать NULL
Результат = МокСоединение.Получить("/test");
Ожидаем.Что(Результат).Равно(NULL);
```
### Использование матчеров
Для переопределения результатов методов не обязательно передавать точные значения параметров. Можно использовать "матчеры". Матчер - это специальная функция, которая проверяет, что параметр удовлетворяет какому-то условию.
```bsl
МокОбъект = Мок.Получить(Тип("Структура"));
// Заставим структуру для проверки всех свойств возвращать "Истина"
МокОбъект.Когда().Свойство(Матчеры.ЛюбаяСтрока()).ТогдаВозвращает(Истина);
// Теперь любой вызов метода "Свойства" с переданной строкой будет возвращать "Истина"
Ожидаем.Что(МокОбъект.Свойство("Строка")).Равно(Истина);
Ожидаем.Что(МокОбъект.Свойство("ДругаяСтрока")).Равно(Истина);
// Вызов функции, например, с числом, продолжит возвращать NULL
Ожидаем.Что(МокОбъект.Свойство("ДругаяСтрока")).Равно(NULL);
```
Матчер - это функция, которая должна вернуть `Истина` или `Ложь`. Вы можете написать матчер любой сложности, используся специальный конструктор.
```bsl
// Функция-матчер принимает минимум один параметр
// Значение - Произвольный - само проверяемое значение
//
// В функции могут содержаться дополнительные параметры. Значения таких параметров должны передаваться
// в виде массива при создании матчера.
//
Функция БольшеТрех(Знач Значение) Экспорт
Возврат Значение > 3;
КонецФункции
МокОбъект = Мок.Получить(Тип("Структура"));
СвойМатчер = Новый Матчер(ЭтотОбъект, "БольшеТрех");
МокОбъект.Когда().Свойство(СвойМатчер).ТогдаВозвращает(Истина);
Ожидаем.Что(МокОбъект.Свойство(0)).Равно(NULL);
Ожидаем.Что(МокОбъект.Свойство(3)).Равно(NULL);
Ожидаем.Что(МокОбъект.Свойство(4)).Равно(Истина);
```
### Переопределение с использованием Ответов
В сложных тестовых случаях методов `ТогдаВозвращает` и `ТогдаВыбрасываетИсключение` может не хватать. Вы можете реализовать более сложную логику ответа с использованием метода `ТогдаОтвечает`
```bsl
// Допустим у нас есть функция, которая просто возвращает строковую информацию
// о вызванном методе.
Функция ВернутьИнформациюОВызове(Знач ИнформацияОВызове) Экспорт
// Параметр ИнформацияОВызове хранит данные о самом моке, вызываемом методе,
// и массиве параметров, с которым вызвали этот метод.
МокОбъект = ИнформацияОВызове.Мок();
ИмяМетода = ИнформацияОВызове.ИмяМетода();
Параметры = ИнформацияОВызове.Параметры();
// Преобразование массива в строку.
Параметры = ПроцессорыКоллекций.ИзКоллекции(Параметры).ВСтроку(", ");
// Произовльное возвращаемое значение
Возврат СтрШаблон("Вызван метод <%1> с параметрами <%2>", ИмяМетода, Параметры);
КонецФункции
// Создадим указатель на функцию, которая должна вызываться при "ответе"
Ответ = Новый Ответ(ЭтотОбъект, "ВернутьИнформациюОВызове");
МокОбъект = Мок.Получить(Тип("Структура"));
// Когда у мока вызывается метод Свойство(), срабатывает вызов функции, заложенной в "Ответе"
МокОбъект.Когда().Свойство(Матчеры.ЛюбаяСтрока(), Матчеры.ЛюбоеЗначение()).ТогдаОтвечает(Ответ);
// Вызовем функцию
Результат = МокОбъект.Свойство("Поле");
// В "Результате" получим строку, возвращенную функцией ВернутьИнформациюОВызове
Ожидаем.Что(Результат).Равно("Вызван метод <Свойство> с параметрами <Поле, >");
```
### Проверка вызова методов
```bsl
// Допустим у нас есть класс, принимающий в себя HTTPСоединение, и вызывающий у него метод Получить()
// Проверим, что метод Получить() действительно вызывался
МойКласс = Новый МойКласс();
МокСоединение = Мок.Получить(Новый HTTPСоединение("localhost"));
МойКласс.УстановитьКонтекст(МокСоединение);
МойКласс.ВызватьМетодКоторыйДолженДернутьПолучить("/ping");
// Если метод Получить не вызывался, будет выдано исключение
МокСоединение.ПроверитьЧтоВызывалсяМетод().Получить("/ping");
```
### Режим "шпиона" (spy)
```bsl
// Создаем нового шпиона над Структурой
МокСтруктура = Мок.Следить(Новый Структура);
// Шпион вызывает реальные методы объекта
МокСтруктура.Вставить("Ключ1", 1);
// Методы "внутреннего" объекта работают как обычно
Ожидаем.Что(МокСтруктура.Количество()).Равно(1);
МокСтруктура.Вставить("Ключ2", 2);
// Однако, мы можем все еще можем переопределить (stub) результат работы любого метода
МокСтруктура.Когда().Количество().ТогдаВозвращает(999);
// В этом случае будет возвращаться наше значение.
Ожидаем.Что(МокСтруктура.Количество()).Равно(999);
```
## Имеющиеся ограничения
* В силу ограничений движка на создание методов с именами, совпадающими с именами глобальных методов, не от всех объектов можно создать идентичный мок. Например, если создать мок от `Массив`, то метод `Найти()`, совпадающий по имени с глобальным методом, будет переименован в метод `_Найти()`. `Структура` же замокается без проблем.