我正在尝试将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()
})
})
});
答案 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()
});