测试 Node.js,模拟并测试所需的模块?

问题描述 投票:0回答:3

我正在努力围绕我的节点模块编写高质量的测试。问题是需要模块系统。我希望能够检查某个所需的模块是否有方法或其状态是否已更改。似乎有两个相对较小的库可以在这里使用:node-gentlymockery。然而,由于他们的低调,这让我认为要么人们没有测试这个,要么有另一种我不知道的方法可以做到这一点。

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

unit-testing testing node.js mocking require
3个回答
12
投票

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

node-sandbox 的工作原理与下面所述相同,但包含在一个很好的模块中。我发现合作非常愉快。


-------------- 详细的遮阳篷 ---------------

经过多次试验,我发现在模拟事物的同时单独测试节点模块的最佳方法是使用 Vojta Jina 的方法在具有新上下文的虚拟机内运行每个模块,如here所述。

使用此测试虚拟机模块:

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

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

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

我强烈推荐这种方式来单独编写有效的测试。只有验收测试才应该影响整个堆栈。单元和集成测试应该测试系统的隔离部分。


5
投票

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

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

测试时,我可以发送模拟、空对象,无论什么看起来合适。请注意,我不会对所有依赖项执行此操作,基本上仅对 IO 执行此操作 - 我觉得不需要测试我的代码是否调用

path.join
或其他内容。

我认为“低调”让你紧张有以下几个原因:

  • 有些人的代码结构与我的类似
  • 有些人有自己的助手来实现与嘲笑等人相同的目标(这是一个非常简单的模块)
  • 有些人不会对这些东西进行单元测试,而是启动他们的应用程序实例(和数据库等)并对其进行测试。更干净的测试,服务器速度很快,不会影响测试性能。

简而言之,如果您认为嘲笑适合您,那就去做吧!


1
投票

您可以使用“a”轻松模拟 require:https://npmjs.org/package/a

//Example faking require('./foo') in unit test:
var fakeFoo = {};
var expectRequire = require('a').expectRequire;
expectRequire('./foo').return(fakeFoo);
    
    
//in sut:
var foo = require('./foo'); //returns fakeFoo
© www.soinside.com 2019 - 2024. All rights reserved.