javascript - 在 promise 解析时调用私有(private)函数的单元测试模块

标签 javascript node.js unit-testing chai

我是 Node 单元测试的新手,在 promise 方面遇到了障碍。我的模块通过 ApiController 执行搜索,然后返回一个 promise 。根据其解析状态,它调用模块内的两个私有(private)函数之一。

模块:

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 获取结果(同时仍然调用私有(private)函数)?

最佳答案

如果方法的作用域为闭包或为模块私有(private),则无法访问它们,只能间接验证。要提供 fetchResults 的测试实现,必须以某种方式公开它。

一种方法是 require ApiController (这可能已经发生),然后使用 proxyquiremockery覆盖依赖关系。我使用过许多测试套件,它们交互和提供测试依赖项的唯一方法是通过修补 require。使用这种方法测试套件变成了一场噩梦。清理、取消补丁、级联补丁,所有这些都会耗费大量时间,如果有其他选择,我们建议不要这样做。

另一种方法是将 fetchResults 实现更改为对象的能力。除了测试之外,使 fetchResults 可配置将有助于使您的代码免受 future 更改的影响,因为当/如果您需要获取结果的方式发生变化时,可以最大限度地减少对 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 了,所以我不确定对上述对象建模的最佳方法,但重要的是,如果您的测试想要重写实现,那么实现必须是暴露,上面的代码应该这样做)

现在有一个 Results 对象,其中的 fetchResults 方法以易于重写的方式公开

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

上面公开了返回函数和错误函数,这也允许对该功能进行隔离的单元测试。

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

结果.process

关于javascript - 在 promise 解析时调用私有(private)函数的单元测试模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42595505/

相关文章:

javascript - 如何在 $.ajax 调用后停止执行 JS 代码,即当服务器正在处理 AJAX 请求时

node.js - Travis CI 作业失败,结果未知 "configured"

javascript - 如何将数据从一个函数传递到作为第一个函数的参数的另一个函数

javascript - Sinon.js stub 并测试以对象为参数的外部函数调用,稍后由 ref 修改

javascript - IndexedDBShim 工作了一段时间,然后产生错误

javascript - redux-form 和 react-select onChange 不会更新 redux 值

javascript - 为什么以下函数没有选择该指令内的所有复选框?

node.js - Sequelize 包含嵌套对象数组 - node.js

unit-testing - PHPUnit:模拟不存在的类

c# - 在其他测试中使用 Microsoft fakes 时单元测试变慢