1

我有以下 JavaScript:

var async = require('async');

var MyOutputModel = function(persistenceModel, callback) {
    async.each(persistenceModel.helpOffers, function(helpOffer, asyncCallback) {
        console.log('Original source (loop)');
        //Do something ...
        asyncCallback();
    }, function(err) {
        console.log('Original source (done)');
        console.log(err);
        if(err) return callback(err);
        return callback(null, _this);
    });
};
module.exports = MyOutputModel;

我想测试包含if(err) return callback(err);...的路径

为此,我看到使用 rewire ( https://www.npmjs.com/package/rewire ) 进行依赖注入的唯一可能性。

在我的单元测试中:

var rewire = require('rewire');    
var MyOutputModel = rewire('...');

var AsyncMock = function() {};
AsyncMock.prototype.each = function(array, successCallback, errorCallback) {
    console.log('Inside mock!');
    callback(new Error());
};
var asyncMock = new AsyncMock();

MyOutputModel.__set__('async', asyncMock); //Rewire for require-dependency-injection

//Act
new CdObjectOutputModel(cdObjectPersistenceModel, function(err, cdObjectOutputModel) {

    //Assert
    assert(err);
});

然而,“模拟”似乎没有被使用。在我的单元测试中,我从来没有在'Inside mock!'控制台上看到过。并且没有错误。'Original source (loop)''Original source (done)'

我做错什么了吗?我已经将 rewire 用于类似的用例,并且效果很好。还是有其他方法?

4

2 回答 2

0

这就是rewire引擎盖下的作用:

  1. 对于每个重新连接的路径,它实际上会读取路径指向的文件的内容,我们将其称为body
  2. 它还会生成两个字符串,第一个称为 theprelude并且它有一些有用的 var 以避免用 覆盖全局的__set__,例如,如果我们想覆盖全局console,就好像它在我们的模块上是本地的一样,则preludevar 的内容会be: var console = global.console,可以在本地覆盖的全局变量的这种很棒的检测在这里完成
  3. 第二个叫做 the appendix,这个字符串实际上包含了 the 的定义,__set__还有__get__source __with__ 每个都是一个定义的函数,module.exports但请记住我们仍在处理字符串
  4. 想象一下,有一种方法可以用字符串创建一个假/测试模块!就是wired这样,它将prelude、 thebody和 the连接appendix到一个大字符串中,然后创建一个模块require('module')

例如(记住这是一个大字符串)

// prelude start
var console = global.console
// a lot of globals that can be overriden are defined here :)
// prelude end

// body start
// I'll paste the contents of the rewire's README
var fs = require("fs");
var path = "/somewhere/on/the/disk";
function readSomethingFromFileSystem(cb) {
    console.log("Reading from file system ...");
    fs.readFile(path, "utf8", cb);
}
exports.readSomethingFromFileSystem = readSomethingFromFileSystem;
// body end

// appendix start
// generation of three functions to set the variables defined above
Object.defineProperty(module.exports, '__set__', {
  enumerable: false,
  value: function () {
    // set contents, we will see this later
  }
});
Object.defineProperty(module.exports, '__get__', { ... });
Object.defineProperty(module.exports, '__with__', { ... });
// appendix end

那么rewire用这个字符串创建一个模块并返回它,瞧你有一个具有三个附加属性的神奇模块,下一步实际上是找出它是做什么__set__源代码归结为以下操作:__set__

function (key, value) {
  eval(key + ' = ' + value);
}

就是这样,所以现在我们知道执行__set__只会评估var您想要的任何键(对我们来说是任何 local ),设置为value在此测试/伪造模块中。

现在回到你的问题,我发现这可能是它的根源:

new CdObjectOutputModel(...);

我假设它CdObjectOutputModel可能被定义为的子类,MyOutputModel但请记住,在您的测试var MyOutputModel = rewire('...');中实际上是一个测试/假模块,因此您并没有真正覆盖原始代码,MyOutputModel而是覆盖仅存在于本地的副本类型,我猜测您必须重新接线,CdObjectOutputModel或者可能在本地CdObjectOutputModel从重新接线的版本继承MyOutputModel

于 2015-03-05T05:51:06.600 回答
0

只需用 errorCallback 替换回调,它应该可以正常工作。

于 2015-10-21T05:03:37.247 回答