Saya memiliki modul ES6 berikut:
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() {
...
}
}
Saya mencari cara untuk menguji Widget dengan contoh tiruan getDataFromServer
. Jika saya menggunakan <script>
modul terpisah s bukannya ES6, seperti di Karma, saya bisa menulis tes saya seperti:
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();
});
});
Namun, jika saya menguji modul ES6 secara individual di luar browser (seperti dengan Mocha + babel), saya akan menulis sesuatu seperti:
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();
});
});
Oke, tapi sekarang getDataFromServer
tidak tersedia di window
(well, tidak ada window
sama sekali), dan saya tidak tahu cara menyuntikkan barang langsung ke dalam widget.js
ruang lingkup sendiri.
Jadi kemana saya harus pergi dari sini?
- Apakah ada cara untuk mengakses ruang lingkup
widget.js
, atau setidaknya mengganti impornya dengan kode saya sendiri? - Jika tidak, bagaimana saya bisa membuat
Widget
diuji?
Hal-hal yang saya pertimbangkan:
Sebuah. Injeksi ketergantungan manual.
Hapus semua impor dari widget.js
dan harapkan penelepon memberikan deps.
export class Widget() {
constructor(deps) {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
Saya sangat tidak nyaman dengan mengacaukan antarmuka publik Widget seperti ini dan mengekspos detail implementasi. Tidak pergi.
b. Ekspos impor untuk memungkinkan mengejek mereka.
Sesuatu seperti:
import { getDataFromServer } from 'network.js';
export let deps = {
getDataFromServer
};
export class Widget() {
constructor() {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
kemudian:
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();
});
});
Ini kurang invasif tetapi mengharuskan saya untuk menulis banyak boilerplate untuk setiap modul, dan masih ada risiko saya menggunakan, getDataFromServer
bukan deps.getDataFromServer
sepanjang waktu. Saya gelisah tentang hal itu, tapi sejauh ini ide terbaik saya.
createSpy
( github.com/jasmine/jasmine/blob/… ) dengan referensi yang diimpor ke getDataFromServer dari modul 'network.js'. Jadi, dalam file tes widget Anda akan mengimpor getDataFromServer, dan kemudian akanlet spy = createSpy('getDataFromServer', getDataFromServer)
spyOn
pada objek itu, diimpor dari network.js
modul. Itu selalu referensi ke objek yang sama.
Widget
antarmuka publik? Widget
kacau tanpa deps
. Mengapa tidak membuat ketergantungan secara eksplisit?