Node.js stubbing request.get()立即调用回调

时间:2016-06-11 13:34:58

标签: node.js unit-testing mocha sinon proxyquire

我正在尝试测试一个在其中调用request.get()函数的函数。
我正在尝试的是覆盖回调函数的所有分支。我试图在不将回调函数分离到不同函数的情况下实现它,因为它使用了上部闭包的变量。

这是一个例子来说明.. foo.js:

var request = require('request');

function func(arg1, arg2) {
    request.get({...}, function(error, response, body) {
        // do stuff with arg1 and arg2 // want to be covered
        if (...) { // want to be covered
        ... // want to be covered
        } else if (...) { // want to be covered
        ... // want to be covered
        } else {
        ... // want to be covered
        }
    });
}

exports.func = func;

我试图用sinon和proxyquire来存根。

foo.spec.js(与sinon衔接):

var foo = require('./foo'),
var sinon = require('sinon'),
var request = require('request');

var requestStub = sinon.stub(request, 'get', function(options, callback) {
    callback(new Error('Custom error'), {statusCode: 400}, 'body');
}); // Trying to replace it with a function that calls the callback immediately so not to deal with async operations in test

foo.func(5, 3);

foo.spec.js(带有proxyquire的存根):

var requestStub = {};

var proxyquire = require('proxyquire'),
var foo = proxyquire('./foo', {'request': requestStub}),
var sinon = require('sinon');

requestStub.get = function(options, callback) {
    callback(new Error('Custom error'), {statusCode: 400}, 'body');
}; // Trying to replace it with a function that calls the callback immediately so not to deal with async operations in test

foo.func(5, 3);

两者都没有奏效。当我尝试调试时,我从未点击回调函数,这表明我没有正确地存储request.get()方法,使其仍然是异步操作。 我很感激有人告诉我在两种情况下我做错了什么(sinon& proxyquire)以及如何修复它的例子。

1 个答案:

答案 0 :(得分:0)

这是使用sinonmocha的单元测试解决方案:

index.js

var request = require("request");

function func(arg1, arg2) {
  request.get("https://github.com/mrdulin", function(error, response, body) {
    console.log(arg1, arg2);
    if (error) {
      console.log(error);
    } else if (response.status === 200) {
      console.log(response);
    } else {
      console.log("others");
    }
  });
}

exports.func = func;

index.spec.js

var foo = require("./");
var sinon = require("sinon");
var request = require("request");

describe("func", () => {
  afterEach(() => {
    sinon.restore();
  });
  it("should handle error", () => {
    const logSpy = sinon.spy(console, "log");
    const getStub = sinon.stub(request, "get");
    foo.func(1, 2);
    const mError = new Error("network error");
    getStub.yield(mError, null, null);
    sinon.assert.calledWith(
      getStub,
      "https://github.com/mrdulin",
      sinon.match.func
    );
    sinon.assert.calledWith(logSpy.firstCall, 1, 2);
    sinon.assert.calledWith(logSpy.secondCall, mError);
  });

  it("should handle response", () => {
    const logSpy = sinon.spy(console, "log");
    const getStub = sinon.stub(request, "get");
    foo.func(1, 2);
    const mResponse = { status: 200 };
    getStub.yield(null, mResponse, null);
    sinon.assert.calledWith(
      getStub,
      "https://github.com/mrdulin",
      sinon.match.func
    );
    sinon.assert.calledWith(logSpy.firstCall, 1, 2);
    sinon.assert.calledWith(logSpy.secondCall, mResponse);
  });

  it("should handle other situation", () => {
    const logSpy = sinon.spy(console, "log");
    const getStub = sinon.stub(request, "get");
    foo.func(1, 2);
    const mResponse = { status: 500 };
    getStub.yield(null, mResponse, null);
    sinon.assert.calledWith(
      getStub,
      "https://github.com/mrdulin",
      sinon.match.func
    );
    sinon.assert.calledWith(logSpy.firstCall, 1, 2);
    sinon.assert.calledWith(logSpy.secondCall, "others");
  });
});

覆盖率100%的单元测试结果:

  func
1 2
Error: network error
    at Context.it (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/src/stackoverflow/37764363/index.spec.js:1:4103)
    at callFn (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runnable.js:387:21)
    at Test.Runnable.run (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runnable.js:379:7)
    at Runner.runTest (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:535:10)
    at /Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:653:12
    at next (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:447:14)
    at /Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:457:7
    at next (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:362:14)
    at Immediate._onImmediate (/Users/ldu020/workspace/github.com/mrdulin/mocha-chai-sinon-codelab/node_modules/mocha/lib/runner.js:425:5)
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)
    ✓ should handle error (48ms)
1 2
{ status: 200 }
    ✓ should handle response
1 2
others
    ✓ should handle other situation


  3 passing (58ms)

---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |      100 |      100 |      100 |      100 |                   |
 index.js      |      100 |      100 |      100 |      100 |                   |
 index.spec.js |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|

源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/37764363