用mochatestingasynchronous函数

我想testing一个运行在node.js中的asynchronousJavaScript函数,并向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); } 

执行此代码的作品和响应将按预期方式显示。

如果我在一个摩卡testing中执行这个请求不执行:

 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。

任何人都可以帮忙吗?

你必须指定callback函数作为提供给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)的签名指定了两个参数,但是当您在testing中调用它时,您提供了三个参数。

摩卡可能找不到方法doRequest(arg1,arg2,arg3)

它没有提供一些错误输出? 也许你可以改变摩卡选项来获得更多的信息。

编辑:

andho是正确的,第二个断言将被并行调用assert.doesNotThrow而只能在成功callback中调用。

我已经修复了示例代码。

编辑2:

或者,为了简化error handling(请参阅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); }); }); }); 

我在一个http客户端的项目中做了一个非常类似的testing。 我在这里粘贴代码,希望是有用的。 这里是客户端(我的nodejs服务器使用快递,我使用承诺error handling):

 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(); }); } 

这是testing:

 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(); }); }); }); 

如果您有一个不支持callback的asynchronous函数,或者您认为使用不必要的callback是不必要的,那么您也可以将testing转换为asynchronoustesting。

代替:

 it('should be able to do something', function () {}); 

干脆做:

 it('should be able to do something', async function () {}); ^^^^^ 

现在,您可以awaitasynchronousfunction:

 it('should be able to do something', async function () { this.timeout(40000); var result = await someComplexFunction(); assert.isBelow(results, 3); });