У мене є наступні модулі 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
. Чому б не зробити залежність явною?