unit testing模块在承诺解决时调用私有函数

我是Node的unit testing新手,在承诺方面遇到了障碍。 我的模块通过ApiController执行search,然后返回一个promise。 根据其parsing状态,它调用模块中的两个私有函数之一。

模块:

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

testing:

 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返回的承诺,以便它实际上不从API获取结果(同时仍然调用私有函数)?

如果方法的作用范围是闭包,或者对于模块是私有的,那么就无法访问它们,只能间接地进行validation。 为了提供fetchResults的testing实现,它必须以某种方式公开。

一种方法是require ApiController (这可能已经发生),然后使用proxyquiremockery来覆盖依赖。 我已经与很多testing套件合作过,只有这样才能进行交互,并且通过修补require提供testing依赖关系。 testing套件成为使用这种方法的噩梦。 清理,不打补丁,级联补丁,都成为巨大的时间汇,如果还有其他的select,将会推荐它。

另一种方法是烘烤将fetchResults实现更改为对象的能力。 除了testing之外,使fetchResultsconfiguration将有助于将您的代码与未来的更改隔离开来,通过帮助最大限度地减lessprocess时的影响/如果您需要获取结果更改:

 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,所以我不确定最好的方法来build模上述对象,但重要的是,如果你的testing要重写一个实现比实现必须暴露,上面的代码应该这样做)

现在有一个结果对象,其中fetchResults方法以容易被fetchResults方式公开

 var fakeFetchResults = sinon.stub(); fakeFetchResults.return(aFakePromiseWithResultsToTriggerResultsCodePath); Results.fetchResult = fakeFetchResults; 

上面展示了返回函数和错误函数,它们也允许对这个函数进行单独的unit testing。

使用过程是通过结果对象完成的,您的控制器可以注册

Results.process