У мене є наступні модулі 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, як у Кармі, я міг би написати свій тест на зразок:
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і очікуйте, що той, хто телефонує, надасть послуги.
export class Widget() {
constructor(deps) {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
Мені дуже незручно зіпсувати загальнодоступний інтерфейс віджетів, як це, та викладати деталі щодо імплементації. Не йдіть.
б. Розкрийте імпорт, щоб дозволити знущатися над ними.
Щось на зразок:
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весь час. Мені це неприємно, але це моя найкраща ідея поки що.
createSpy( github.com/jasmine/jasmine/blob/… ) із імпортованою посиланням на getDataFromServer з модуля 'network.js'. Отже, у тестовий файл віджета ви імпортуєте getDataFromServer, а потімlet spy = createSpy('getDataFromServer', getDataFromServer)
spyOnна тому об'єкті, імпортованому з network.jsмодуля. Це завжди посилання на один і той же об’єкт.
Widgetпублічний інтерфейс? Widgetплутається без deps . Чому б не зробити залежність явною?