gpt4 book ai didi

javascript - 如何模拟 ES6 模块的导入?

转载 作者:IT王子 更新时间:2023-10-29 02:38:11 27 4
gpt4 key购买 nike

我有以下 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();
});
});

好的,但是现在getDataFromServerwindow 中不可用(好吧,根本没有 window),而且我不知道有什么方法可以将东西直接注入(inject) widget.js自己的范围。

那么我该从这里去哪里呢?

  1. 有没有办法访问 widget.js 的范围? ,或者至少用我自己的代码替换它的导入?
  2. 如果没有,我如何制作Widget可测试?

我考虑的事情:

一个。手动依赖注入(inject)。

widget.js 中删除所有导入并期望调用者提供 deps。

export class Widget() {
constructor(deps) {
deps.getDataFromServer("dataForWidget")
.then(data => this.render(data));
}
}

我对像这样弄乱 Widget 的公共(public)接口(interface)并暴露实现细节感到非常不舒服。不行。


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每时每刻。我对此感到不安,但这是我迄今为止最好的主意。

最佳答案

我已经开始在我的测试中使用 import * as obj 风格,它将模块中的所有导出作为对象的属性导入,然后可以模拟该对象。我发现这比使用 rewire 或 proxyquire 或任何类似技术要干净得多。例如,当需要模拟 Redux 操作时,我最常这样做。以下是我可能会在上面的示例中使用的内容:

import * as network from 'network.js';

describe("widget", function() {
it("should do stuff", function() {
let getDataFromServer = spyOn(network, "getDataFromServer").andReturn("mockData")
let widget = new Widget();
expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
expect(otherStuff).toHaveHappened();
});
});

如果您的函数恰好是默认导出,那么 import * as network from './network' 将生成 {default: getDataFromServer} 并且您可以模拟网络.默认。

注意:ES 规范将模块定义为只读,许多 ES 转译器已经开始尊重这一点,这可能会打破这种 spy 方式。这在很大程度上取决于您的转译器和测试框架。例如,尽管 Jasmine does not, at least currently,我认为 Jest 施展了一些魔法来使这项工作成功。 . YMMV.

关于javascript - 如何模拟 ES6 模块的导入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35240469/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com