我是Node的单元测试的新手,并且在承诺方面遇到了障碍。我的模块通过ApiController执行搜索,然后ApiController返回一个promise。根据其解析状态,它将调用模块中的两个私有函数之一。
模块:
module.exports.process = function(req, res) {
let searchTerm = req.query.searchValue;
ApiController.fetchResults(searchTerm)
.then((results) => onReturnedResults(results), (err) => onNoResults());
function onReturnedResults(results) {
req.app.set('searchResults', results);
res.redirect('/results');
}
function onNoResults() {
res.render('search/search', { noResultsFound: true });
}
};
测试:
var res = {
viewName: '', data : {},
render: function(view, viewData) {
this.view = view;
this.viewData = viewData;
}
};
var req = { query: { searchValue: 'doesnotexist' } }
describe('When searching for results that do not exist', function() {
it('should display a no results found message', function(done) {
let expectedResult = {
noResultsFound: true;
}
SearchController.process(req, res);
// Assert...
expect(res.viewData).to.be.equal(expectedResult);
done();
});
})
围绕此问题的最佳做法是什么?我如何模拟' fetchResults返回了promise,因此它实际上并没有从API中获取结果(同时仍在调用私有函数)?
答案 0 :(得分:1)
如果方法的范围是闭包或者是模块专用的,那么就无法访问它们,只能间接验证。要提供fetchResults
的测试实现,必须以某种方式公开它。
一种方法是require
ApiController
(这可能已经发生),然后使用proxyquire
或mockery
来覆盖依赖关系。我曾与许多测试套件合作,他们只能通过修补require
进行交互并提供测试依赖关系。使用此方法,测试套件成为一场噩梦。清理,取消修补,级联补丁,都会成为巨大的时间汇,如果有其他选择,会建议不要使用它。
另一种方法是烘焙将fetchResults
实现更改为对象的功能。除了测试之外,fetchResults
可配置还有助于将代码与未来的更改隔离开来,有助于在需要获取结果的方式发生变化时将process
的影响降至最低:
var Results = (function() {
return {
process: function(req, res) {
let searchTerm = req.query.searchValue;
this.fetchResults(searchTerm)
.then((results) => this.onReturnedResults(req, res, results), (err) => this.onNoResults(res)),
fetchResults: ApiController.fetchResults,
onReturnedResults: function(req, res, results) {
req.app.set('searchResults', results);
res.redirect('/results');
},
onNoResults: function(res) {
res.render('search/search', { noResultsFound: true });
}
};
})()
(我暂时没有使用javascript,所以我不确定对上述对象进行建模的最佳方法,但重要的是如果你的测试想要覆盖一个实现而不是必须公开实现,上面的代码应该这样做)
现在有一个结果对象,fetchResults
方法以易于覆盖的方式公开
var fakeFetchResults = sinon.stub();
fakeFetchResults.return(aFakePromiseWithResultsToTriggerResultsCodePath);
Results.fetchResult = fakeFetchResults;
以上公开了返回功能和错误功能,它还允许对该功能进行隔离单元测试。
使用过程通过结果对象完成,您的控制器可以注册
Results.process