在整个项目中存根请求

Stubbing request across entire project

我正在为一个小型 REST 库编写测试,该库在 request 库之上实现 OAuth 的刷新授权。作为其功能的一部分,它提供了一个重试功能,在 rest.js:

中具有类似的功能
const auth = require('./auth');
const request = require('request');

function retry(headers, responseHandler) {
  headers.auth.bearer = auth.getToken();
  request(headers, function(err, resp) {
    if (resp.error && resp.error == 'invalid_token') {
      return auth.renew(function(e, r) { retry(headers, responseHandler); });
    }
    // handle happy case
  });
});

auth.renew 所做的是将 headers 中的信息和内部已知的刷新令牌发布到令牌提供者。重要的一点是它通过使用 request.post 将递归事件处理程序向下传递到请求库来实现。

当然,当我对此进行测试时,我不希望传出 HTTP 调用。所以我用 sinon 把它们去掉:

const requestStub = sinon.stub(),
    rest = proxyquire('./rest', { 'request': requestStub }),
    authFail = { error: 'invalid_token' },
    authSuccess = { token: '123' };

describe('#retry', () => {
  it('calls retry twice on failed auth', () => {
    requestStub.yields(null, authFail);
    requestStub.post = sinon.stub().yields(null, authSuccess);

    retry({}, () => {});
    sinon.assert.calledTwice(requestStub);
  });
});

问题是 auth.renew 很高兴自己继续 require('request'),因此再也看不到我的存根了。所以我想我的问题是: 如何让 auth 使用我存根的 request 而不是它自己的?

我知道 sinon 可以 stub XHR,但这似乎是我想要的很多低级努力。

所以我想到的解决方案是替换整个 auth.renew 方法,所以事情看起来像这样:

const requestStub = sinon.stub(),
    rest = proxyquire('./rest', { 'request': requestStub, 
      './auth': { 
        renew: function(callback) {
          requestStub.yields(null, authSuccess);
          callback();
        }
    }),
    authFail = { error: 'invalid_token' },
    authSuccess = { token: '123' };

describe('#retry', () => {
  it('calls retry twice on failed auth', () => {
    requestStub.yields(null, authFail);

    retry({}, () => {});
    sinon.assert.calledTwice(requestStub);
  });
});