测试Node.js,模拟并测试已经需要的模块?

hen*_*ald 6 testing unit-testing mocking require node.js

我正努力在我的节点模块周围编写高质量的测试.问题是require模块系统.我希望能够检查某个必需模块是否有方法或其状态已更改.似乎有两个相对较小的库可以在这里使用:节点 - 轻轻嘲弄.然而,由于它们的"低调",它让我觉得要么人们不测试这个,要么就是我不知道的另一种做法.

模拟和测试所需模块的最佳方法是什么?

hen*_*ald 11


----------- 更新 ---------------

node-sandbox在如下所述的相同主体上工作,但是包含在一个很好的模块中.我发现很高兴能与之合作.


--------------- 详细的awnser ---------------

多次试验之后,我发现测试节点模块隔离,同时嘲讽的东西出来是Vojta开发集纳使用的方法来运行虚拟机内部各模块用新的上下文解释的最佳途径这里.

使用此测试vm模块:

var vm = require('vm');
var fs = require('fs');
var path = require('path');

/**
 * Helper for unit testing:
 * - load module with mocked dependencies
 * - allow accessing private state of the module
 *
 * @param {string} filePath Absolute path to module (file to load)
 * @param {Object=} mocks Hash of mocked dependencies
 */
exports.loadModule = function(filePath, mocks) {
  mocks = mocks || {};

  // this is necessary to allow relative path modules within loaded file
  // i.e. requiring ./some inside file /a/b.js needs to be resolved to /a/some
  var resolveModule = function(module) {
    if (module.charAt(0) !== '.') return module;
    return path.resolve(path.dirname(filePath), module);
  };

  var exports = {};
  var context = {
    require: function(name) {
      return mocks[name] || require(resolveModule(name));
    },
    console: console,
    exports: exports,
    module: {
      exports: exports
    }
  };

  vm.runInNewContext(fs.readFileSync(filePath), context);
  return context;
};
Run Code Online (Sandbox Code Playgroud)

可以使用自己的上下文测试每个模块,并轻松删除所有外部依赖项.

fsMock = mocks.createFs();
mockRequest = mocks.createRequest();
mockResponse = mocks.createResponse();

// load the module with mock fs instead of real fs
// publish all the private state as an object
module = loadModule('./web-server.js', {fs: fsMock});
Run Code Online (Sandbox Code Playgroud)

我强烈建议这种方式单独编写有效的测试.只有验收测试才能达到整个堆栈.单元和集成测试应测试系统的隔离部分.


Lin*_*iel 5

我认为嘲弄模式很好.也就是说,我通常选择将依赖项作为参数发送到函数(类似于在构造函数中传递依赖项).

// foo.js
module.exports = function(dep1, dep2) {
    return {
        bar: function() {
            // A function doing stuff with dep1 and dep2
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在测试时,我可以发送模拟,空对象,无论什么看起来合适.请注意,我不会为所有依赖项执行此操作,基本上只有IO - 我觉得不需要测试我的代码调用path.join或其他什么.

我认为让你紧张的"低调"是由于以下几点:

  • 有些人将他们的代码构造成与我的相似
  • 有些人有自己的帮助者实现与mockery等人相同的目标(这是一个非常简单的模块)
  • 有些人不对这些东西进行单元测试,而是调整他们的app(和db等)的实例并对其进行测试.清洁测试,服务器速度很快,不会影响测试性能.

简而言之,如果你认为嘲弄适合你,那就去吧!