2013-08-28 4 views
2

Я использую промежуточное ПО save в Mongoose для создания журнала активности в БД всякий раз, когда предпринимаются какие-либо действия. Что-то вродеТестирование асинхронных промежуточных функций с Mongoose

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, но это кажется мне взломанным. Есть ли способ протестировать асинхронные операции промежуточного ПО Mongoose?

ответ

1

К сожалению, нет возможности надежно чередоваться с этими двумя асинхронными функциями так, как вам хотелось бы (поскольку нет потоков, вы не можете «приостановить» выполнение). Они могут выполнить несогласованный порядок, который оставляет вам решения, такие как тайм-аут.

Я предлагаю вам подключить обработчик событий к классу Activity, чтобы при записи/сбое активности он просматривал список помещенных в очередь (хешированных?) Действий, которые должны регистрироваться. Итак, когда создается действие, добавьте в список ("onactivitycreated")). Затем оно будет записано(), сравните и удалите успехи (не уверен, что имеет смысл с моккой). Когда ваши тесты завершены, вы можете увидеть, список пуст.

вы можете использовать util.inherits(Activity, EventEmitter), например, расширить класс Activity с функциональностью событий.

Теперь, вы все равно придется подождать/тайм-аут в списке, если были ошибки, которые не были обработанные событиями, вам также нужно будет это обработать.

Редактировать - проигнорируйте предложение ниже как интересную демонстрацию as ync, который не будет работать для вас. :)

Если вы хотите, чтобы проверить их, я бы взглянуть на библиотеку как 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); 
}); 
+0

'waterfall' будет иметь такую ​​же проблему, поскольку операция промежуточного программного обеспечения может не завершиться, даже если' User.create' делает (и вызывает 'done').Поэтому я думаю, что ответ использует 'setTimeout':/ –

+0

Вы говорите, что вызов Create полностью завершен (не возвращается вообще и не вызывает обратный вызов)? – WiredPrairie

+0

Нет, 'create' отлично работает, но в вашем примере' done' вызывается до завершения 'Activity.create', поэтому' .find' ничего не найдет. –

0

Асинхронный после сохранения промежуточного уровня, видимо, будет доступен в Мангуста 4.0.0:

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

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

На данный момент, вы можете обойти это обезьяна-латание сохранения в документе, чтобы он поддерживал промежуточное ПО async 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);} 
    ); 

    }); 
}; 

 Смежные вопросы

  • Нет связанных вопросов^_^