如何存根request.get三次?有2个相同的网址和1个不同的网址?

时间:2019-01-31 14:48:58

标签: request sinon node-request sinon-chai

我需要为以下代码编写单元测试用例。这些网址是外部api调用,因此我需要模拟这些。对于其余的测试用例,我使用了sinon。因此,只想在 sinon 中编写这些内容。

function 1 {
  async.waterfall() {
    function 2();
    function 3();
  }
}

function 2(callback) {
    url2_1 = "/calculatorFunctionList"
    request.get(url2_1,function (err, res, body) {
        return callback("with some diff response")
    })}

function 3(callback) {
    url3_1 = "addition/values="+somevalue1
    url3_2 = "addition/values="+somevalue2
    request.get(url3_1,function (err, res, body) {
        if(!err) {
            request.get(url3_2, function (err, res, body) {
                return callback("with some response")
            })
        }
    })
}

我需要对这些请求进行存根。我怎样才能做到这一点?还有如何以及何时调用存根的恢复,以免与其他请求存根混淆?目前,两个存根都没有被嘲笑。

1 个答案:

答案 0 :(得分:0)

Sinon-的核心(暂时忘了lolexnise)-显式处理javascript函数的存根和监视。而已。它本身与模块加载器或Node 本身无关。

因此,它不知道如何连接到Node的模块加载器(require)并自行解决依赖关系。对于一般情况,您有两种选择:

  1. 为模块(测试中的系统)提供注入点(例如function setRequestModule(module){ request = module }),这些注入点可用于提供Sinon存根。
  2. 使用链接级来拦截对模块系统的调用,以加载依赖项并将其换出。有关如何操作,请参见this article on Sinon's how-to section

那是通常的情况,但是由于您要处理网络级别的存根,因此存在第三个选项,该选项与第二个选项有关,这涉及到挂接Node的http层并在其中设置伪造的请求和响应使用nock

这看起来像这样:

const nock = require('nock')

const scope = nock('https://api.github.com')
  .get('/repos/atom/atom/license')
  .reply(200, {
    license: {
      key: 'mit',
      name: 'MIT License',
      spdx_id: 'MIT',
      url: 'https://api.github.com/licenses/mit',
      node_id: 'MDc6TGljZW5zZTEz',
    },
  })

这是我通常会做的事情,但是由于您坚持只使用Sinon,因此您将获得第一个选择。

第一个选项的阐述:注入依赖项

您的函数23(无效的javascript标识符,btw)都依赖于模块request及其方法get来获得结果。为了能够控制request.get返回的内容,您需要为您的模块提供request不同版本以供测试。这可以使用依赖注入来完成。

首先,我假设您的函数以request模块的导入开始,这意味着前几行包含如下语句:

const request = require('request');

您需要更改此语句,以便可以替换request常量,这意味着它现在看起来像这样:

let request = require('request');

为了能够控制您的依赖关系,您现在可以向导出添加新功能:

module.exports.setRequestModule = function (stub){
    request = stub;
}

要在测试中使用此功能,则需要在测试中执行此操作:

const myModule = require('../src/my-module');
const myRequestStub = {};

myModule.setRequestModule(myRequestStub);

it('should return the expected response', () => {
    const expectedOutput = "with some response";
    myRequestStub.get = function (url, callback) {
         callback(null, expectedOutput);
    }

    myModule.doSomething() ...
    // do test
});

或者 您还可以在模块中暴露请求对象:

module.exports._request = request;

例如,您可以使用sinon通过在测试中插入get方法来对其进行检测。

const myModule = require('../src/my-module');

sinon.stub(myModule._request, 'get').callsFake( (url, cb) => cb("hello!") );