在摩卡testing中的for循环中进行顺序mongoose查询

我正在尝试使用摩卡作为我的API应用程序的testing驱动程序。

我有一个用户名json的歌曲名称,我试图提供给一个API端点。

JSON:

{ "description": "hold the lists that each user heard before", "userIds":{ "a": ["m2","m6"], "b": ["m4","m9"], "c": ["m8","m7"], "d": ["m2","m6","m7"], "e": ["m11"] } } 

比方说,用户和歌曲模式只是名称的_id。 我想要做的是在parsingjson文件之后,通过按名称对“a”进行mongoose查找,将“a”转换为user_id,让我们说id = 0。 将每个“m2”转换为名称为“song_id”的id = 1,然后调用请求http:// localhost:3001 / listen / 0/1

这是我迄今为止的我的摩卡testing:

test.js:

 it('adds the songs the users listen to', function(done){ var parsedListenJSON = require('../listen.json')["userIds"]; //console.log(parsedListenJSON); for (var userName in parsedListenJSON) { if (parsedListenJSON.hasOwnProperty(userName)) { var songs = parsedListenJSON[userName]; var currentUser; //console.log(userName + " -> " + songs); var userQuery = User.findOne({'name': userName}) userQuery.then(function(user){ //console.log("user_id: " + user["_id"]); currentUser = user; }); for (var i=0; i<songs.length; i++) { //console.log(songs[i]); var songQuery = Song.findOne({'name': songs[i]}) songQuery.then(function(song){ console.log("user_id: " + currentUser["_id"]); console.log("song_id: " + song["_id"]); // need to ensure we have both the user_id and song_id api_request = "http://localhost:3001/listen/" + currentUser["_id"] + "/" + song["_id"]; console.log(api_request); // listen/user_id/song_id //.post('http://localhost:3001/listen/0/1') request .post(api_request) .end(function(err, res){ expect(res.status).to.equal(200); }); }); } } } done(); }) 

问题:

1)我需要确保在调用API之前,我有user_id和song_id。 现在,每个User.findOne和Song.findOne查询都有自己的then子句。 我通过currentUservariables将user_id传递到Song查询的then块中。 但由于查询是asynchronous的,我不认为这是正确的。 如何构造这段代码,以便在then块同时执行时继续进行API调用。

2)当我运行代码时,只有第一个用户得到执行,而不是其余的,即。 打印出来是:user_id:0 song_id:1 http:// localhost:3001 / listen / 0/1 user_id:0 song_id:5 http:// localhost:3001 / listen / 0/5

3)API端点与邮递员一起工作,下面是一个更简单的摩卡testing。 但它似乎并没有在我的原始代码中工作。

 var request = require('superagent'); var expect = require('expect.js'); var User = require('../models/user'); var Song = require('../models/song'); var mongoose = require('mongoose'); mongoose.connect('localhost/TestSongRecommender'); ... it('adds the songs', function(){ request .post('http://localhost:3001/listen/0/2') .end(function(res){ expect(res.status).to.equal(200); }); }); 

更新:

async.forEach方法起作用。 这是我的最后一个片段:

更新了test.js

 var request = require('superagent'); var expect = require('expect.js'); var async = require('async'); var User = require('../models/user'); var Song = require('../models/song'); var mongoose = require('mongoose'); mongoose.connect('localhost/Test'); describe('song recommendations', function(){ it('adds the songs the users listen to', function(done){ var parsedListenJSON = require('../listen.json')["userIds"]; //console.log(parsedListenJSON); async.forEach(Object.keys(parsedListenJSON), function forAllUsers(userName, callback) { var songs = parsedListenJSON[userName]; //var currentUser; //console.log(userName + " -> " + songs); var userQuery = User.findOne({'name': userName}) userQuery.then(function(user){ //console.log("user_id: " + user["_id"]); //console.log(songs); //currentUser = user; async.forEach(songs, function runSongQuery(songName, smallback) { //console.log(songName); var songQuery = Song.findOne({'name': songName}) songQuery.then(function(song){ //console.log("user_id: " + user["_id"]); //console.log("song_id: " + song["_id"]); // need to ensure we have both the user_id and song_id api_request = "http://localhost:3001/listen/" + user["_id"] + "/" + song["_id"]; console.log(api_request); // listen/user_id/song_id //.post('http://localhost:3001/listen/0/1') request .post(api_request) .end(function(err, res){ expect(res.status).to.equal(200); smallback() }); }); }, function allSongs(err) { callback(); }) }); }, function allUserNames(err) { done() }) }) }); 

1&2)你将要使用NPM的asynchronous包。 您可以使用命令npm install async --save在您的主文件夹中,并在您的代码中使用var async = require('async')

你必须用async.forEachreplace每个循环。 async.forEach接受一个数组和两个函数作为参数。 它调用数组中每个项目的第一个函数,一旦所有的callback都返回,则调用第二个函数。

你现在正在做的,用循环的方式是行不通的。 在asynchronous事件返回的时候,你的循环已经遍历它们了(非阻塞IO,记住),你的variables不能正确设置。

您还需要设置所有代码运行后才能调用的东西。

如果编写得当,它最终会看起来像这样:

 it('adds the songs the users listen to', function(done){ var parsedListenJSON = require('../listen.json')["userIds"]; //console.log(parsedListenJSON); async.forEach(parsedListenJSON, function forAllUsers(userName, callback) { var songs = parsedListenJSON[userName]; //console.log(userName + " -> " + songs); var userQuery = User.findOne({'name': userName}) userQuery.then(function(user){ //console.log("user_id: " + user["_id"]); var currentUser = user; async.forEach(songs, function runSongQuery(songName, smallback) { var songQuery = Song.findOne({'name': songName}) songQuery.then(function(song){ console.log("user_id: " + currentUser["_id"]); console.log("song_id: " + song["_id"]); // need to ensure we have both the user_id and song_id api_request = "http://localhost:3001/listen/" + currentUser["_id"] + "/" + song["_id"]; console.log(api_request); // listen/user_id/song_id //.post('http://localhost:3001/listen/0/1') request .post(api_request) .end(function(res){ expect(res.status).to.equal(200); smallback() }); }); }, function allRan(err) { callback(); }) }); }, function allUserNames(err) { done() }) }) 

3)你将要使用testing框架来testing你的API。 我推荐supertest 。 一旦你超超,要求你的应用程序和超特性:

 var request = require('supertest'); var app = require('./testApp.js'); 

在testing中使用它:

 request(app) .post(api_request) .end(function(res){ expect(res.status).to.equal(200); smallback() });