J'ai les modules ES6 suivants:
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() {
...
}
}
Je cherche un moyen de tester Widget avec une instance simulée de getDataFromServer
. Si j'utilisais des <script>
s séparés au lieu de modules ES6, comme dans Karma, je pourrais écrire mon test comme:
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();
});
});
Cependant, si je teste les modules ES6 individuellement en dehors d'un navigateur (comme avec Mocha + babel), j'écrirais quelque chose comme:
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();
});
});
D'accord, mais maintenant getDataFromServer
n'est pas disponible dans window
(enfin, il n'y en a pas window
du tout), et je ne connais pas un moyen d'injecter des trucs directement dans son widget.js
propre scope.
Alors, où dois-je partir d'ici?
- Existe-t-il un moyen d'accéder à la portée de
widget.js
, ou au moins de remplacer ses importations par mon propre code? - Sinon, comment puis-je rendre
Widget
testable?
Les choses que j'ai envisagées:
une. Injection manuelle de dépendances.
Supprimez toutes les importations widget.js
et attendez de l'appelant qu'il fournisse les deps.
export class Widget() {
constructor(deps) {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
Je suis très mal à l'aise de gâcher l'interface publique de Widget comme celle-ci et d'exposer les détails de mise en œuvre. Ne pas aller.
b. Exposez les importations pour permettre de les moquer.
Quelque chose comme:
import { getDataFromServer } from 'network.js';
export let deps = {
getDataFromServer
};
export class Widget() {
constructor() {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}
puis:
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();
});
});
Ceci est moins invasif mais m'oblige à écrire beaucoup de passe-partout pour chaque module, et il y a toujours un risque que j'utilise getDataFromServer
au lieu de deps.getDataFromServer
tout le temps. Je suis inquiet à ce sujet, mais c'est ma meilleure idée jusqu'à présent.
createSpy
( github.com/jasmine/jasmine/blob/… ) avec une référence importée à getDataFromServer à partir du module 'network.js'. Pour que, dans le fichier de tests du widget, vous importiez getDataFromServer, puis vous feriezlet spy = createSpy('getDataFromServer', getDataFromServer)
spyOn
sur cet objet, importé du network.js
module. C'est toujours une référence au même objet.
Widget
l'interface publique de? Widget
est foiré sans deps
. Pourquoi ne pas rendre la dépendance explicite?