У меня есть следующие модули 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() {
...
}
}
Я ищу способ протестировать виджет с помощью фиктивного экземпляра getDataFromServer
. Если бы я использовал отдельные <script>
s вместо модулей 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
тестируемым?
Я рассмотрел:
а. Внедрение зависимостей вручную.
Удалите весь импорт из widget.js
и ожидайте, что вызывающий предоставит deps.
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
все время. Меня это беспокоит, но пока это моя лучшая идея.