在mocha测试中的for循环中进行顺序mongoose查询

时间:2016-07-04 15:41:02

标签: node.js mongoose mocha

我正在尝试将mocha用作我的API应用程序的测试驱动程序。

我有一个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。我想要做的是解析json文件后,转换" a"通过对" a"进行mongoose查找来访问user_id。按名称,我们说id = 0。转换每个" m2"按名称进入song_id,让我们说id = 1,然后打电话 请求http://localhost:3001/listen/0/1

以下是我目前为摩卡测试所做的事情:

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 cal之前,我需要确保我同时拥有user_id和song_id。现在,User.findOne和Song.findOne查询中的每一个都有自己的then子句。我将user_id通过currentUser变量传递给Song查询的then块。但由于查询是异步的,我不认为这是正确的。如何构造此代码,以便在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端点适用于邮递员,并在下面的简单Mocha测试中使用。但它似乎不适用于我的原始代码。

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 个答案:

答案 0 :(得分:1)

1&amp; 2)您将要使用NPM的异步包。您可以使用主文件夹中的npm install async --save命令和代码中的var async = require('async')来获取它。

您必须使用async.forEach替换每个for循环。 async.forEach接受一个数组和两个函数作为参数。它会在数组中的每个项目上调用第一个函数,并在返回所有回调后调用第二个函数。

你目前使用for循环的方式不起作用。当异步事件返回时,你的循环已经迭代过了它们(非阻塞IO,请记住)并且你的变量不再正确设置。

只有在所有代码运行完毕后,您还需要设置调用完成的内容。

如果写得恰到好处,最终会看起来像这样:

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)您将要使用测试框架来测试您的API。我推荐this issue。一旦你有了超级优惠,就需要你的app和supertest:

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

在以下测试中使用它:

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