[英]Testing asynchronous function with mocha
我想測試一個在node.js中運行的異步javascript函數,並向http api發出一個簡單的請求:
const HOST = 'localhost';
const PORT = 80;
http = require('http');
var options = {
host: HOST,
port: PORT,
path: '/api/getUser/?userCookieId=26cf7a34c0b91335fbb701f35d118c4c32566bce',
method: 'GET'
};
doRequest(options, myCallback);
function doRequest(options, callback) {
var protocol = options.port == 443 ? https : http;
var req = protocol.request(options, function(res) {
var output = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log(chunk);
output += chunk;
});
res.on('error', function(err) {
throw err;
});
res.on('end', function() {
var dataRes = JSON.parse(output);
if(res.statusCode != 200) {
throw new Error('error: ' + res.statusCode);
} else {
try {
callback(dataRes);
} catch(err) {
throw err;
}
}
});
});
req.on('error', function(err) {
throw err;
});
req.end();
}
function myCallback(dataRes) {
console.log(dataRes);
}
執行此代碼有效,響應將按預期顯示。
如果我在mocha測試中執行此操作,則不執行請求:
describe('api', function() {
it('should load a user', function() {
assert.doesNotThrow(function() {
doRequest(options, myCallback, function(err) {
if (err) throw err;
done();
});
});
assert.equal(res, '{Object ... }');
});
});
問題是,之后沒有代碼:
var req = protocol.request(options, function(res) {
甚至沒有一個簡單的console.log執行。
有人可以幫忙嗎?
您必須將done
的回調指定為提供給mocha的函數的參數 - 在本例中為it()
函數。 像這樣:
describe('api', function() {
it('should load a user', function(done) { // added "done" as parameter
assert.doesNotThrow(function() {
doRequest(options, function(res) {
assert.equal(res, '{Object ... }'); // will not fail assert.doesNotThrow
done(); // call "done()" the parameter
}, function(err) {
if (err) throw err; // will fail the assert.doesNotThrow
done(); // call "done()" the parameter
});
});
});
});
此外, doRequest(options, callback)
的簽名指定了兩個參數,但是當您在提供三個參數的測試中調用它時。
摩卡可能找不到方法doRequest(arg1,arg2,arg3)
。
它沒有提供一些錯誤輸出嗎? 也許您可以更改mocha選項以獲取更多信息。
編輯:
andho是對的,第二個斷言將與assert.doesNotThrow
並行調用,而它只應在成功回調中調用。
我修復了示例代碼。
編輯2:
或者,為了簡化錯誤處理(參見Dan M.的評論):
describe('api', function() {
it('should load a user', function(done) { // added "done" as parameter
assert.doesNotThrow(function() {
doRequest(options, function(res) {
assert.equal(res, '{Object ... }'); // will not fail assert.doesNotThrow
done(); // call "done()" the parameter
}, done);
});
});
});
如果您有一個不支持回調的異步函數,或者您認為使用不必要的回調是......不必要的話,那么您也可以將測試轉換為異步測試。
代替:
it('should be able to do something', function () {});
簡單地說:
it('should be able to do something', async function () {});
^^^^^
現在你可以await
異步函數:
it('should be able to do something', async function () {
this.timeout(40000);
var result = await someComplexFunction();
assert.isBelow(result, 3);
});
我在我的項目中為一個http客戶端做了一個非常類似的測試。 我在這里粘貼代碼,希望是有用的。 這是客戶端(我的nodejs服務器使用express,我使用promise進行錯誤處理):
var http = require('http');
var querystring = require('querystring');
module.exports = {
get: function(action, params, res, callback) {
doPromiseRequest(action, querystring.stringify(params), callback, 'GET', 'application/json')
.then((response) => callback(response))
.catch((error) => {
res.status(500);
res.render('error', {layout: false, message: error.message, code: 500});
});
},
}
function doPromiseRequest(action, params, callback, method, contentType) {
var options = {
hostname: 'localhost',
port: 3000,
path: '/api/v1/' + action.toString(),
method: method,
headers: {
'Content-Type': contentType,
'Content-Length': Buffer.byteLength(params)
}
};
return new Promise( (resolve, reject) => {
var req = http.request(options,
function(response) {
response.setEncoding('utf8');
var data = '';
response.on('data', function(chunk) {
data += chunk;
});
response.on('end', function() {
var parsedResponse;
try {
parsedResponse = JSON.parse(data);
} catch(err) {
reject({message: `Invalid response from hurricane for ${action}`});
return;
}
if (parsedResponse.error)
reject(parsedResponse.error);
else
resolve(parsedResponse);
});
response.on('error', function(err){
console.log(err.message);
reject(err);
});
});
req.on('error', function(err) {
console.log(err);
reject({message: err.message});
});
req.write(params);
req.end();
});
}
以下是測試:
var http = require('http');
var expect = require('chai').expect;
var sinon = require('sinon');
var PassThrough = require('stream').PassThrough;
describe('Hurricane Client tests', function() {
before(function() {
this.request = sinon.stub(http, 'request');
});
after(function() {
http.request.restore();
});
it('should convert get result to object', function(done) {
var expected = { hello: 'world' };
var response = new PassThrough();
response.statusCode = 200;
response.headers = {}
response.write(JSON.stringify(expected));
response.end();
var request = new PassThrough();
this.request.callsArgWith(1, response).returns(request);
client.get('any', {}, null, function(result) {
expect(result).to.eql(expected);
done();
});
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.