【问题标题】:Writing tests for javascript module using webpack's require.ensure function使用 webpack 的 require.ensure 函数为 javascript 模块编写测试
【发布时间】:2015-10-11 21:50:06
【问题描述】:

我正在我的服务器上运行 mocha 测试,以一种独立的单元测试方式测试源脚本。

我正在测试的一个脚本调用了 Webpack 的 require.ensure 函数,当它被 Webpack 捆绑时,它对于在应用程序中创建代码分割点很有用。

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

我试图为这个函数创建某种 polyfill/stub/mock/spy,但没有任何运气。

有一个包,webpack-require,它允许创建 webpack 上下文。这可以工作,但速度慢得令人无法接受。我希望有某种轻量级的 polyfill 直接针对 require.ensure 函数。

有什么建议吗? :)


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

mocha 测试加载一个人为的模块,其中包含一个方法,如果定义了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;
  });
});

【问题讨论】:

    标签: javascript node.js unit-testing mocha.js webpack


    【解决方案1】:

    好的,经过大量研究和深思熟虑,我终于有了答案。

    我最初认为我可以使用某种 IoC / DI 策略来解决这个问题,但后来我找到了负责加载模块的 source code for Node JS's Module library。查看源代码,您会注意到模块的“require”函数(即我的示例中的 foo.js)是由 _compile function of NodeJs's module loader 创建的。它是内部范围的,我看不到修改它的直接机制。

    我不太确定 Webpack 如何或在何处扩展创建的“require”实例,但我怀疑它带有一些黑魔法。我意识到我需要一些帮助来做类似的事情,并且不想为此编写大量复杂的代码。

    然后我偶然发现rewire...

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

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

    • 为其他模块注入模拟
    • 泄露私有变量
    • 覆盖模块内的变量。
    • rewire 不加载文件并评估内容以模拟节点的要求机制。事实上,它使用节点自己的 require 来加载模块。因此,您的模块在测试环境中的行为与常规情况下完全相同(除了您的修改)。

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

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

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

    啊啊啊……好开心。快速运行测试再次登陆。

    哦,在我的情况下不需要它,但如果您通过 webpack 捆绑代码以进行基于浏览器的测试,那么您可能需要 rewire-webpack 插件。我还在某处读到这可能与 ES6 语法有问题。

    另一个注意事项:对于 require(...) 语句的直接模拟,我建议使用 mockery 而不是 rewire。它不如 rewire(没有私有变量访问)强大,但在我看来这更安全一些。此外,它还有一个非常有用的警告系统,可以帮助您不要进行任何无意的嘲弄。


    更新

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-24
      • 1970-01-01
      • 1970-01-01
      • 2021-06-10
      • 2016-07-26
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      相关资源
      最近更新 更多