2012-03-05 143 views
6

我正在努力围绕我的节点模块编写高质量的测试。问题是需求模块系统。我希望能够检查某个需要的模块是否有方法或其状态已更改。似乎有两个相对较小的库可用于此处:node-gentlymockery。然而,由于他们的'个人资料'较低,这让我认为任何人都不会对此进行测试,或者有另一种做法,我不知道。测试Node.js,模拟并测试一个需要的模块?

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

回答

10

----------- UPDATE在同校长---------------

node-sandbox作品说明以下,但被包裹在一个很好的模块中。我发现与它合作非常愉快。


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

经过多次试验我找到最好的方法来孤立地测试节点模块,同时嘲笑事情的方法是使用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; 
}; 

有可能测试每个模块都有自己的背景,轻松地踩灭了所有外部dependencys。

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

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

+0

感谢您的好评!然而,我有另一个问题: 我无法利用这种技术来覆盖被测模块中我自己定制函数的私有函数。它会产生两个函数:一个在本地范围内,另一个在全局范围内,被测模块始终调用全局/原始版本。 – Attilah 2014-12-13 23:24:00

5

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

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

当测试时,我可以发送模拟,空的对象,而不是看起来合适。请注意,我不这样做所有依赖关系,基本上只有IO - 我不觉得需要测试我的代码调用path.join或其他任何。

我认为“低调”,也就是让你紧张是因为两件事情:

  • 有人结构上类似于他们的代码来挖掘
  • 有些人有他们自己的助手履行相同作为嘲笑等目标(这是一个非常简单的模块)
  • 有些人不会单元测试这样的事情,而是旋转他们的应用程序(和数据库等)的实例和测试。更清洁的测试,服务器速度如此之快,不会影响测试性能。

总之,如果你认为嘲笑适合你,那就去吧!

+0

的问题,这是单元测试更是创下这是不理想的数据库。 – 2012-06-03 11:10:50

+1

@beck:只有当你在测试时发送一个真实的分贝。 – 2012-06-03 12:51:10

1

您可以轻松地嘲笑通过使用“一”要求: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