使用webpack的require.ensure函数为javascript模块编写testing

我在我的服务器上运行摩卡testing,testing源脚本是一种单独的unit testing方式。

我正在testing的一个脚本调用了Webpack的require.ensure函数,这个函数在被Webpack绑定的时候在应用程序中创build代码分割点是非常有用的。

我为这个脚本编写的testing不在Webpack上下文中运行,因此require.ensure函数不存在,testing失败。

我试图为这个函数创build一些polyfill / stub / mock / spy,但是没有任何运气。

有一个包, webpack-require ,它允许创build一个webpack上下文。 这可以工作,但速度慢得令人难以接受。 我宁愿有一些直接针对require.ensure函数的轻量级require.ensure

任何build议? 🙂


这是一个非常基本的摩卡testing起点。

摩卡testing加载一个包含方法的人工模块,如果require.ensure被定义,则返回true。

foo.js

 export default { requireEnsureExists: () => { return typeof require.ensure === 'function'; } }; 

foo.test.js

 import { expect } from 'chai'; describe('When requiring "foo"', () => { let foo; before(() => { foo = require('./foo.js'); }); it('The requireEnsureExists() should be true', () => { expect(foo.requireEnsureExists()).to.be.true; }); }); 

好的,经过多方研究和思考,我终于得到了答案。

我最初以为我可以使用某种IoC / DI策略来解决这个问题,但是后来我find了负责加载模块的Node JS的模块库的源代码 。 看看源代码,你会注意到模块的'require'函数(例如我的例子中的foo.js )是由NodeJs的模块加载器的_compile函数创build的。 它的内部范围,我看不到一个即时修改它的机制。

我不太确定Webpack如何或在哪里扩展创build的“require”实例,但我怀疑这是一些黑魔法。 我意识到,我需要一些帮助来做类似的事情,而不想写一大堆复杂的代码来这样做。

然后我偶然发现了…

node.js应用程序的dependency injection。

rewire增加了一个特殊的setter和getter模块,所以你可以修改他们的行为,以更好的unit testing。 你可以

  • 注入其他模块的模拟
  • 泄漏私有variables
  • 覆盖模块内的variables。
  • 重新连接不加载文件并评估内容以模拟节点的需求机制。 实际上它使用节点自己的要求来加载模块。 因此,您的模块在testing环境中的行为与正常情况下的行为完全相同(除了您的修改)。

完善。 访问私有variables是我所需要的。

安装rewire后,让我的testing工作很容易:

foo.js

 export default { requireEnsureExists: () => { return typeof require.ensure === 'function'; } }; 

foo.test.js

 import { expect } from 'chai'; import rewire from 'rewire'; describe('When requiring "foo"', () => { let foo; before(() => { foo = rewire('./foo.js'); // Get the existing 'require' instance for our module. let fooRequire = moduletest.__get__('require'); // Add an 'ensure' property to it. fooRequire.ensure = (path) => { // Do mocky/stubby stuff here. }; // We don't need to set the 'require' again in our module, as the above // is by reference. }); it('The requireEnsureExists() should be true', () => { expect(foo.requireEnsureExists()).to.be.true; }); }); 

Aaaaah ….太高兴了。 快速运行testing土地。

哦,在我的情况下,这是不需要的,但如果你是通过webpack绑定你的代码的基于浏览器的testing,那么你可能需要rewire-webpack插件。 我也读过这个地方,这可能有ES6语法的问题。

另外一个注意事项:为了直接嘲弄require(…)语句,我build议使用嘲讽而不是rewire。 它不像rewire那么强大(没有私有variables访问),但是在我看来这更安全一些。 此外,它有一个非常有用的警告系统,以帮助您不要做任何无意的嘲弄。


更新

我也看到了以下战略正在被采用。 在使用require.ensure每个模块中,检查它是否存在,如果不是,则require.ensure它:

 // Polyfill webpack require.ensure. if (typeof require.ensure !== `function`) require.ensure = (d, c) => c(require);