У меня есть библиотека Typescript, которая экспортирует отдельные функции, которые не связаны вместе в классе, что позволяет им потрясти дерево любым приложением-потребителем через веб-пакет.
Я ищу писать чистые модульные тесты, что легко сделать для большинства функций. Однако есть некоторые составные функции, поведение которых полностью делегировано одной или нескольким функциям.
Пример
В этом примере реализация getType
полностью основана на поведении двух других функции. Поэтому имеет смысл протестировать его, основываясь исключительно на поведении тех, которые называются функциями. Именно поэтому библиотеки тестирования поддерживают шпионаж.
Код библиотеки
export function getType(value: string): 'FOO' | 'BAR' | 'OTHER' {
return isFoo(value) ? 'FOO' : isBar(value) ? 'BAR' : 'OTHER';
}
export function isFoo(value: string): boolean {
const regex = /crazyComplexFooRegex/;
return regex.test(value);
}
export function isBar(value: string): boolean {
const regex = /crazyComplexBarRegex/;
return regex.test(value);
}
Код теста:
import * as FooBarUtils from './foobar-utils';
import createSpy = jasmine.createSpy;
fdescribe('FooBar Utils', () => {
it('getType should return FOO type if isFoo', () => {
(FooBarUtils as any).isFoo = createSpy("isFoo").and.returnValue(true); // ERROR
(FooBarUtils as any).isBar = createSpy("isBar").and.returnValue(false);
expect(FooBarUtils.getType("value doesn't matter")).toBe('FOO');
});
});
В результате получается TypeError: Cannot set property isFoo of [object Module] which has only a getter
.
ПРИМЕЧАНИЕ. На самом деле это часть более крупного Angular CLI-проекта, который включает в себя пакетирование веб-пакетов.
Мысли
- Я пытался использовать старую библиотеку, которая была предназначена для решения этой проблемы, но не смогла с тем же сообщением об ошибке. https://www.npmjs.com/package/ts-mock-imports, но получил те же результаты.
- Я последовал предложению, которое сработало, но потребовало создания кода, связанного с тестированием, ВНУТРИ исходного кода моей библиотеки. Мне это не понравилось, потому что оно нарушило общее правило, согласно которому код не должен делать специальных вещей только для целей тестирования. См. https://railsware.com/blog/mocking-es6-module-import-without-dependency-injection/
- Многие предложения рекомендуют использовать Dependency Injection (DI) для решения проблемы, но для этого требуется, чтобы библиотека реструктурировала себя только для того, чтобы ее можно было протестировать.
Заключительные мысли
Мне кажется, что пространство для решения этой проблемы может заключаться в использовании tsconfig.spe c. json, который настроен так, чтобы TypeScript генерировал меньше инкапсулированных Javascript вывод? Есть ли в Typescript даже опции конфигурации для поддержки этого?
EDIT: Это может быть больше связано с инкапсуляцией Javascript модуля, чем Typescript. Есть идеи?