2

每当采取某些操作时,我都会在 Mongoose 中使用save中间件在数据库中创建活动日志。就像是

UserSchema.post("save", function (doc) {
    mongoose.model("Activity").create({activity: "User created: " + doc._id});
});

这似乎工作正常,但问题是我无法测试它,因为没有办法将回调传递post(这可能没有意义)。我使用以下方法对此进行了测试mocha

User.create({name: "foo"}, function (err, user) {
    Activity.find().exec(function (err, act) {
        act[0].activity.should.match(new RegExp(user._id));
        done();
    });
});

问题是在调用Activity.create之前显然没有完成。.find我可以通过包裹来解决这个.find问题setTimeout,但这对我来说似乎很老套。有什么方法可以测试异步猫鼬中间件操作吗?

4

2 回答 2

1

不幸的是,没有办法以您想要的方式可靠地交错这两个异步函数(因为没有线程,您不能“暂停”执行)。它们可以以不一致的顺序完成,这使您可以解决诸如超时之类的问题。

我建议您将事件处理程序连接到 Activity 类,以便当 Activity 写入/失败时,它会查看应记录的排队(散列?)活动列表。所以,当一个活动被创建时,添加到列表("onactivitycreated")。然后,它最终会被写入("onactivitywritten"),比较和删除成功可能(不确定摩卡有什么意义)。当你的测试完成后,你可以看看列表是否空的。

util.inherits(Activity, EventEmitter)例如,您可以使用事件功能扩展 Activity 类。

现在,您仍然需要在列表中等待/超时,如果存在未通过事件处理的故障,您也需要处理。

编辑——忽略下面的建议,因为它是一个有趣的异步演示,它不适合你。:)

如果您想测试它们,我会看一下像async这样的库,您可以在其中执行一系列代码(或waterfall在本例中),以便您可以首先创建一个User,然后,一旦它完成,确认Activity已记录正确。我在waterfall这里使用过,以便可以将值从一个任务传递到下一个任务。

async.waterfall([
    function(done) {
       User.create({name: "foo"}, function (err, user) {
           if (err) { done(err); return; }
           done(null, user._id);  // 2nd param sent to next task as 1st param
       });

    },
    function(id, done) {  // got the _id from above
        // substitute efficient method for finding
        // the corresponding activity document (maybe it's another field?)
        Activity.findById(id, function (err, act) {
            if (err) { done(err); return; }
            if (act) { done(null, true);
            done(null, false); // not found?!
        });
    }
], function(err, result) {
   console.log("Success? " + result);
});
于 2013-08-28T19:34:52.683 回答
0

Mongoose 4.0.0 中显然会提供异步保存后中间件:

https://github.com/LearnBoost/mongoose/issues/787

https://github.com/LearnBoost/mongoose/issues/2124

目前,您可以通过猴子修补文档上的 save 方法来解决此问题,以便它支持异步 post-save 中间件。以下代码在与您类似的情况下为我工作。

// put any functions here that you would like to run post-save
var postSave = [
  function(next) {
    console.log(this._id);
    return next();
  }
];

var Model = require('mongoose/lib/model');

// monkey patch the save method
FooSchema.methods.save = function(done) {
  return Model.prototype.save.call(this, function(err, result) {
    if (err) return done(err, result);

    // bind the postSave functions to the saved model
    var fns = postSave.map(function(f) {return f.bind(result);});
    return async.series(fns,
      function(err) {done(err, result);}
    );

  });
};
于 2014-09-25T22:54:31.900 回答