我正在尝试编写一个单元/集成测试,我希望在这里获得数据库中的事物列表。不是它只是一个GET,但这些测试需要扩展到POST,PUT& DELETE
到目前为止我的代码工作得很好,我实际上可以从数据库中获取数据,但是一旦我尝试删除负责调用DB的函数,Mocha超时
1失败
1)/ account_types GET 200列表: 错误:超过2000毫秒的超时。确保在此测试中调用done()回调。 在null。 (C:\代码\ JS \ general_admin_service \ node_modules \摩卡\ lib中\ runnable.js:215:19)
我理解没有调用done()回调,因为代码卡在某处,但是,我不明白我做错了什么。
我使用以下参考资料来了解我的位置:
我的代码如下:
测试:
'use strict';
var expect = require('chai').expect,
request = require('supertest'),
chance = require('chance').Chance(),
server = require('../server'),
sinon = require('sinon'),
select = require('../../helpers/data_access/select');
describe("/account_types", function () {
before(function(done){
sinon
.stub(select, "query_list")
.returns([{id: "test"}]);
done();
});
after(function(done){
select
.query_list
.restore();
done();
});
it('GET 200 List', function (done) {
request(server.baseURL)
.get('/api/v1/account_types')
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json')
.expect(200)
.end(function (err, res) {
/* istanbul ignore if */
if (err)
return done(err);
expect(res.body).to.include.keys('result');
expect(res.body.result).to.not.be.null;
expect(res.body.result).to.not.be.undefined;
expect(res.body.result).to.be.an('Array');
expect(res.body.result.length).to.be.above(0);
//expect(select.query_list).to.have.been.calledOnce;
return done();
});
});
});
Restify endpoint:
var select = require('../helpers/data_access/select')
module.exports = function (server) {
var query = "..."
return select.query_list(res, next, db_config, query);
});
};
select.js:
var sql = require('mssql');
module.exports = {
query_list: function (res, next, config, sql_query) {
return query(res, next, config, sql_query, true);
},
query_single: function (res, next, config, sql_query) {
return query(res, next, config, sql_query, false);
}
};
function query(res, next, config, sql_query, isList) {
var connection = new sql.Connection(config);
connection.connect(function (err) {
if (err) {
return on_error(err, res);
}
var request = new sql.Request(connection);
request.query(sql_query, function (err, response) {
connection.close();
if (err) {
return on_error(err, res);
}
if (isList) {
return return_list(res, response, next);
} else {
return return_single(res, response, next);
}
});
});
}
function on_error(error, res, next) {
res.status(500).send(error);
return next();
}
function return_list(res, response, next) {
res.send({result: response});
return next();
}
function return_single(res, response, next) {
res.send({result: response[0]});
return next();
}
我期望发生的是因为我存在query_list函数,如果我希望在我的预期之后放置console.log(res.body.result);
,我应该看到[{id: "test"}]
的返回,但是显然没有达到这一点。
我做错了什么?
更新:添加了完整的select.js文件。
答案 0 :(得分:1)
正如您在评论中已经明确指出的那样,测试深度嵌套的代码很困难。
使用回调或承诺通常会好得多,因此应用程序的每个部分都将处理它负责的部分,但不会(更多)。因此,您的路由处理程序将处理请求和响应。显然可以调用其他函数,比如执行数据库查询的函数,但不是让这些函数发回响应,而是使用回调函数“回调”到路由处理程序中的查询结果。
这样的事情:
server.get('/api/v1/account_types', function(req, res, next) {
select.query_list(QUERY, function(err, records) {
if (err) return next(err);
res.send({ results : records });
next();
});
});
在使用Sinon测试这样的事情方面:它实际上取决于确切的实现。我可以提供一个关于如何存根select.query_list
的上述用法的快速示例,以确保响应包含正确的数据。
基本存根看起来像这样:
sinon.stub(select, 'query_list').yieldsAsync(null, [ { id : 'test' } ]);
这样做,就是当select.query_list()
被调用时,它将调用它接收的第一个回调参数(它通过检查每个参数来查看哪个是函数)并使用参数null, [ { id : 'test' } ]
。
这些是处理程序中传递的回调函数的err
和records
参数。因此,您可以使用它来完全跳过数据库查询,并假装查询产生了特定的记录数组。
从那里,res.send()
被调用(这是你最初遇到的问题:它根本没有被调用,因为它是在你的app的一部分中执行的,因为它没有被调用,因为你的存根)你可以检查你的测试结果响应数据是否符合预期。
如果你想在调用堆栈中更深层地存储一个函数,但是使用正确的Sinon工具(如.yields*
,或者使用间谍而不是存根),它会变得有点复杂,它通常不是非常困难(提供您想要存根/间谍的所有功能都是可访问的,即导出的。