使用webpack的require.ensure函数为javascript模块编写测试 [英] Writing tests for javascript module using webpack's require.ensure function

查看:242
本文介绍了使用webpack的require.ensure函数为javascript模块编写测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在服务器上运行Mocha测试,以独立的单元测试方式测试源脚本.

I am running mocha tests on my server, testing source scripts an isolated unit test manner.

我正在测试的脚本之一调用了Webpack的 require.ensure 功能,当Webpack捆绑了应用程序时,该功能对于在应用程序中创建代码拆分点很有用.

One of the scripts I am testing makes a call to Webpack's require.ensure function, which is useful for creating code-splitting points in the application when it gets bundled by Webpack.

我为此脚本编写的测试不在Webpack上下文中运行,因此require.ensure函数不存在,并且测试失败.

The test I have written for this script does not run within a Webpack context, therefore the require.ensure function does not exist, and the test fails.

我试图为此功能创建某种形式的polyfill/stub/mock/spy,但没有任何运气.

I have tried to create some sort of polyfill/stub/mock/spy for this function but have had no luck whatsoever.

有一个软件包, webpack-require ,它确实允许创建webpack语境.这可以工作,但是速度慢得令人无法接受.我希望直接使用require.ensure函数来实现某种轻量级的polyfill.

There is a package, webpack-require, which does allow for the creation of a webpack context. This can work but it is unacceptably slow. I would prefer to have some sort of lightweight polyfill targeting the require.ensure function directly.

有什么建议吗? :)

这是一个非常基本的起点摩卡测试.

Here is a very basic starting point mocha test.

mocha测试加载了一个人为设计的模块,其中包含一个方法,如果定义了require.ensure,则该方法返回true.

The mocha test loads a contrived module containing a method which returns true if require.ensure is defined.

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;
  });
});

推荐答案

好吧,经过大量研究和审议,我终于有了答案.

Ok, I finally have an answer for this after much research and deliberation.

我最初以为我可以使用某种IoC/DI策略来解决此问题,但是后来我找到了

I initially thought that I could solve this using some sort of IoC / DI strategy, but then I found the source code for Node JS's Module library which is responsible for loading modules. Looking at the source code you will notice that the 'require' function for modules (i.e. foo.js in my example) get created by the _compile function of NodeJs's module loader. It's internally scoped and I couldn't see an immediate mechanism by which to modify it.

我不太确定Webpack如何或在哪里扩展创建的"require"实例,但是我怀疑它带有一些黑魔法.我意识到我需要一些帮助来做类似性质的事情,并且不想编写大量复杂的代码来做到这一点.

I am not quite sure how or where Webpack is extending the created "require" instance, but I suspect it is with some black magic. I realised that I would need some help to do something of a similar nature, and didn't want to write a massive block of complicated code to do so.

然后我偶然发现了重新布线 ...

Then I stumbled on rewire...

node.js应用程序的依赖注入.

Dependency injection for node.js applications.

rewire在模块中添加了一个特殊的setter和getter,因此您可以修改它们的行为以进行更好的单元测试.你可以

rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may

  • 为其他模块注入模拟
  • 泄漏私有变量
  • 覆盖模块中的变量.
  • rewire不会加载文件并评估内容以模拟节点的require机制.实际上,它使用节点自身的要求来加载模块.因此,您的模块在测试环境中的行为与正常情况下完全一样(修改后除外).
  • inject mocks for other modules
  • leak private variables
  • override variables within the module.
  • rewire does not load the file and eval the contents to emulate node's require mechanism. In fact it uses node's own require to load the module. Thus your module behaves exactly the same in your test environment as under regular circumstances (except your modifications).

完美.我只需要访问私有变量.

Perfect. Access to private variables is all that I need.

安装rewire之后,使我的测试正常进行很容易:

After installing rewire, getting my test to work was easy:

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 ....太高兴了.快速运行的测试再次降落.

Aaaaah.... so happy. Fast running test land again.

哦,就我而言,这不是必需的,但是如果您是通过webpack捆绑代码以进行基于浏览器的测试,那么您可能需要 rewire-webpack 插件.我还在某个地方读到它可能与ES6语法有关的问题.

Oh, in my case it's not needed, but if you are bundling your code via webpack for browser based testing, then you may need the rewire-webpack plugin. I also read somewhere that this may have problems with ES6 syntax.

另一个注意事项:为了直接模拟require(...)语句,我建议使用模型而不是重新布线.它没有重新连接功能强大(没有私有变量访问权限),但是在我看来,这有点安全.另外,它有一个非常有用的警告系统,可以帮助您避免任何无意的嘲笑.

Another note: for straight up mocking of require(...) statements I would recommend using mockery instead of rewire. It's less powerful than rewire (no private variable access), but this is a bit safer in my opinion. Also, it has a very helpful warning system to help you not do any unintentional mocking.

更新

我还看到了采用以下策略.在每个使用require.ensure的模块中,检查其是否存在,如果不存在,则对其进行填充:

I've also seen the following strategy being employed. In every module that uses require.ensure check that it exists and polyfill it if not:

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

这篇关于使用webpack的require.ensure函数为javascript模块编写测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆