如何对需要其他模块的Node.js模块进行单元测试,以及如何模拟全局require函数?

如何对需要其他模块的Node.js模块进行单元测试,以及如何模拟全局require函数?

问题描述:

这是一个简单的示例,它说明了我的问题的症结所在:

This is a trivial example that illustrates the crux of my problem:

var innerLib = require('./path/to/innerLib');

function underTest() {
    return innerLib.doComplexStuff();
}

module.exports = underTest;

我正在尝试为此代码编写单元测试.如何在不完全模拟require函数的情况下模拟对innerLib的需求?

I am trying to write a unit test for this code. How can I mock out the requirement for the innerLib without mocking out the require function entirely?

所以这是我试图模拟全局require并发现即使这样做也不起作用:

So this is me trying to mock out the global require and finding out that it won’t work even to do that:

var path = require('path'),
    vm = require('vm'),
    fs = require('fs'),
    indexPath = path.join(__dirname, './underTest');

var globalRequire = require;

require = function(name) {
    console.log('require: ' + name);
    switch(name) {
        case 'connect':
        case indexPath:
            return globalRequire(name);
            break;
    }
};

问题是underTest.js文件中的require函数实际上尚未被模拟.它仍然指向全局require函数.因此,似乎只能模拟正在执行模拟的同一文件中的require函数.如果我使用全局require来包含任何内容,即使在覆盖本地副本之后,这些文件仍然需要全局require引用.

The problem is that the require function inside the underTest.js file has actually not been mocked out. It still points to the global require function. So it seems that I can only mock out the require function within the same file I’m doing the mocking in. If I use the global require to include anything, even after I’ve overridden the local copy, the files being required will still have the global require reference.

您现在可以!

我发布了 proxyquire ,它将在测试模块时负责覆盖模块内部的全局需求.

I published proxyquire which will take care of overriding the global require inside your module while you are testing it.

这意味着您无需无需更改代码即可为所需模块注入模拟内容.

This means you need no changes to your code in order to inject mocks for required modules.

Proxyquire有一个非常简单的api,它可以解析您要测试的模块,并通过一个简单的步骤传递其所需模块的模拟/存根.

Proxyquire has a very simple api which allows resolving the module you are trying to test and pass along mocks/stubs for its required modules in one simple step.

@Raynos是正确的,传统上,您必须诉诸不太理想的解决方案才能实现该目标或进行自下而上的开发

@Raynos is right that traditionally you had to resort to not very ideal solutions in order to achieve that or do bottom-up development instead

这是我创建proxyquire的主要原因-允许自上而下的测试驱动开发而没有麻烦.

Which is the main reason why I created proxyquire - to allow top-down test driven development without any hassle.

请查看文档和示例,以判断它是否适合您的需求.

Have a look at the documentation and the examples in order to gauge if it will fit your needs.