2013-08-09 3 views
3

Я пишу тесты для моего проекта Node.js/Express/Mongoose с использованием Mocha и Should.js, и я тестирую свои функции, которые обращаются к моему MongoDB. Я хочу, чтобы эти тесты были полностью независимы от фактических записей в моей базе данных, поэтому я хочу создать запись, а затем загрузить ее и выполнить все мои тесты на ней, а затем удалить ее. У меня есть мои фактические функции (я пишу тесты после завершения всего проекта), так что функция create не имеет обратного вызова; он просто просто отображает страницу, когда это делается. В моем сценарии тестов я вызываю свою функцию load_entry после вызова create, но иногда create занимает больше времени, чем обычно, и поэтому load_entry выдает сообщение об ошибке, когда он не может загрузить эту статью, поскольку она еще не создана. Есть ли способ убедиться, что асинхронная функция закончена без использования обратных вызовов?Дождитесь завершения асинхронной функции без добавления обратного вызова

Пожалуйста, дайте мне знать, если есть дополнительная информация, которую я могу предоставить. Я просмотрел весь Google и не смог найти ничего, что действительно отвечало на мой вопрос, поскольку большинство решений просто говорят «используйте обратный вызов!».

+0

В целях тестирования ознакомьтесь с информацией о sinon.js (доступно на npm). Он позволяет отключать асинхронные вызовы, такие как ajax-вызовы и таймауты и т. Д. Хорошо работает с моккой. – slebetman

ответ

5

Используйте то, что известно как promise

Вы можете прочитать больше об этом here.

Есть много замечательных библиотек, которые могут сделать это за вас.

Q.js это один из тех, что мне лично нравятся, и он широко используется в наши дни. Обещания также существуют в jQuery среди многих других.

Вот пример использования ватного обещания с асинхронным json-p вызова: DEMO

var time; 
$.ajax({ 
    dataType: 'jsonp', 
    type: 'GET', 
    url: "http://www.timeapi.org/utc/now.json", 
    success: function (data) { 
     time = data; 
    }, 
    error: function (data) { 
     console.log("failed"); 
    } 
}) 
.then(function(){ // use a promise library to make sure we synchronize off the jsonp 
    console.log(time);  
}); 
+0

Спасибо, человек! Я ответил на свой вопрос ниже, если вы хотите посмотреть, что я сделал, но это похоже на действительно хороший ответ на использование в будущем! :) – gr3co

+1

Звучит неплохо, рад, что у вас есть рабочее решение! Я настоятельно рекомендую взглянуть на обещания независимо. Обещания - отличный образец. –

1

Это, безусловно, вид, что вы хотите обратный вызов для. Если это не так, вам придется написать какую-то оболочку обратного вызова, которая опросит базу данных, чтобы определить, когда она закончила создание соответствующих записей, а затем испускает событие или делает какую-то другую асинхронную вещь, чтобы тест продолжался.

0

Поскольку единственным родным способом сделать асинхронные вещи являются: setTimeout, setInterval и addEventListener, и все они принимают обратный вызов вы в конечном итоге придется использовать обратный вызов где-нибудь.

Однако вы можете скрыть это, используя Promises/A, также известный как «Отсрочки».

Ваш код может выглядеть следующим образом:

db.create_entry("foo", data).done(function (entry) { 
    db.delete_entry(entry).done(function() { 
     console.log("entry is deleted"); 
    }); 
}); 

Использование тогдашней цепочки:

db.create_entry("foo", data).then(function (entry) { 
    return db.delete_entry(entry); 
}).done(function() { 
    console.log("entry is deleted"); 
});; 
0

Я нашел решение, которое работает. То, что я сделал, чтобы добавить функцию обратного вызова для моей функции (next) и вызывать его, если он указан (то есть, для испытаний):

//more stuff above 
article.save(function(err){ 
    if (!err) { 
     console.log(req.user.username + ' wrote ' + article.slug) 
     return next() || res.redirect('/admin') 
    } 
    return next(err) || res.render('articles/entry_form', { 
     title: 'New Entry', 
     article: article, 
    }) 
}) 

Таким образом, при запуске фактического сервера и не обратного вызова не определен , он не будет вызывать ошибку, потому что он просто вернет оператор res.render.

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