【发布时间】:2016-05-16 09:26:40
【问题描述】:
我有以下 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 的模拟实例来测试 Widget。如果我使用单独的 <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 的公共接口并暴露实现细节感到非常不舒服。不行。
b.公开导入以允许模拟它们。
类似:
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 的风险。我对此感到不安,但这是迄今为止我最好的主意。
【问题讨论】:
-
如果没有对这种导入的 native 模拟支持,我可能会考虑为 babel 编写一个自己的转换器,将您的 ES6 样式导入转换为自定义的可模拟导入系统。这肯定会增加另一层可能的失败并更改您要测试的代码,... .
-
我现在无法设置测试套件,但我会尝试使用 jasmin 的
createSpy(github.com/jasmine/jasmine/blob/…) 函数,并从“network.js”模块导入对 getDataFromServer 的引用。这样,在小部件的测试文件中,您将导入 getDataFromServer,然后将let spy = createSpy('getDataFromServer', getDataFromServer) -
第二个猜测是从 'network.js' 模块返回一个对象,而不是一个函数。这样,您就可以在该对象上使用
spyOn,从network.js模块导入。它始终是对同一个对象的引用。 -
其实它已经是一个对象了,据我所见:babeljs.io/repl/…
-
我真的不明白依赖注入是如何弄乱
Widget的公共接口的?Widget搞砸了没有deps。为什么不明确依赖关系?
标签: javascript unit-testing mocha.js ecmascript-6