У меня есть следующие модули ES6:
network.js
export function getDataFromServer() {
return ...
}
widget.js
import { getDataFromServer } from 'network.js';
export class Widget() {
constructor() {
getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
render() {
...
}
}
Я ищу способ проверить Widget с помощью mock-экземпляра getDataFromServer
. Если бы я использовал отдельные <script>
вместо модулей ES6, как в Karma, я мог бы написать свой тест, например:
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(window, "getDataFromServer").andReturn("mockData")
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
Однако, если я тестирую модули ES6 отдельно вне браузера (например, с Mocha + babel), я бы написал что-то вроде:
import { Widget } from 'widget.js';
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(?????) // How to mock?
.andReturn("mockData")
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
Хорошо, но теперь getDataFromServer
недоступен в window
(ну, там вообще нет window
), и я не знаю, как вводить материал непосредственно в widget.js
собственную область.
Итак, куда мне идти?
- Есть ли способ получить доступ к области
widget.js
или, по крайней мере, заменить его импорт моим собственным кодом? - Если нет, как я могу сделать
Widget
testable?
Материал, который я рассмотрел:
а. Ручная инъекция зависимостей.
Удалите все импорт из widget.js
и ожидайте, что вызывающий абонент предоставит отпечатки.
export class Widget() {
constructor(deps) {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
Мне очень неудобно испортить публичный интерфейс Widget, как это, и разоблачить детали реализации. Нет.
б. Экспортируйте импорт, чтобы высмеивать их.
Что-то вроде:
import { getDataFromServer } from 'network.js';
export let deps = {
getDataFromServer
};
export class Widget() {
constructor() {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
то
import { Widget, deps } from 'widget.js';
describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(deps.getDataFromServer) // !
.andReturn("mockData");
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});
Это менее инвазивно, но требует, чтобы я написал много шаблонов для каждого модуля, и по-прежнему существует риск, что я все время использую getDataFromServer
вместо deps.getDataFromServer
. Я беспокоюсь об этом, но это моя лучшая идея.