Как создать заглушку для интерфейса / определения типа в TypeScript?
Я работаю с Typescript в проекте на AngularJS 1.X и использую различные JavaScript-библиотеки для разных целей. Для юнит-тестирования моего исходного кода я хотел бы замокать некоторые зависимости, используя типы (интерфейсы). Я не хочу использовать тип ANY и не хочу писать пустое тело для каждого метода интерфейса.
Я ищу способ сделать что-то вроде следующего:
let dependency = stub(IDependency);
stub(dependency.b(), () => { console.log("Hello World") });
dependency.a(); // --> Компилируется, ничего не делает, без исключений
dependency.b(); // --> Компилируется, печатает "Hello World", без исключений
У меня сейчас проблема в том, что я либо использую any
и реализую все методы, которые вызываются в моем тесте, либо реализую интерфейс и пишу полную его реализацию. Это слишком много лишнего кода 😦
Как я могу сгенерировать объект, который имеет пустую реализацию для каждого метода и при этом типизирован? Я использую Sinon для мокирования, но готов рассмотреть и другие библиотеки.
P.S. Я знаю, что Typescript удаляет интерфейсы, но мне все равно хотелось бы решить эту задачу.
2 ответ(ов)
Краткий ответ заключается в том, что это невозможно в TypeScript, так как язык не предоставляет возможностей для "рефлексии" на этапе компиляции или выполнения. Мок-библиотекам не под силу итерировать члены интерфейса.
Смотрите обсуждение: https://github.com/Microsoft/TypeScript/issues/1549
Это, к сожалению, создает трудности для разработчиков, использующих TDD, поскольку мокирование зависимости является центральной частью рабочего процесса разработки.
Тем не менее, существует несколько техник для быстрой заглушки методов, как описано в других ответах. Эти варианты могут подойти, если немного адаптировать подход.
Правка: Абстрактное синтаксическое дерево TypeScript (AST) является примером "интроспекции" на этапе компиляции — и его можно было бы использовать для генерации моков. Однако я не знаю, создало ли кто-то практическую библиотеку для этой цели.
В библиотеке ts-mockito появилась возможность мокирования интерфейсов с версии 2.4.0. Для этого вместо передачи типа в функцию mock
, установите тип как обобщение (generic type). Это требует реализации Proxy. Вот пример:
let mockedFoo: Foo = mock<FooInterface>(); // вместо mock(FooInterface)
const foo: SampleGeneric<FooInterface> = instance(mockedFoo);
Для получения дополнительной информации и скачивания новой версии можно ознакомиться с официальной страницей пакета на npm или записью о релизе на GitHub.
Работа с $scope.$emit и $scope.$on в AngularJS
Как привязать значения списка чекбоксов в AngularJS?
Переопределение типа свойства интерфейса, определённого в файле d.ts TypeScript
Как проверить, содержит ли массив строку в TypeScript?
ESLint: 8.0.0 Не удалось загрузить плагин '@typescript-eslint'