与sinon和bluebird一起确定一个有希望的功能

时间:2015-01-30 14:31:20

标签: javascript node.js promise sinon bluebird

在我想测试的文件中,我有以下代码:

var httpGet = Promise.promisify(require("request").get);
httpGet(endpoint, {
    auth: {bearer: req.body.access_token},
    json: true
})
    .then(...)

现在,在我的测试中,我想确保httpGet被调用一次,并确保参数有效。在被宣传之前,我的测试看起来像这样:

beforeEach(function () {
    request.get = sinon.stub()
        .yields(null, null, {error: "test error", error_description: "fake google error."});
});

afterEach(function () {
    expect(request.get).to.have.been.calledOnce();
    var requestArgs = request.get.args[0];
    var uri = requestArgs[0];

    expect(uri).to.equal(endpoint);
    //...
});

不幸的是,当request.get被宣传时,这不再有效。我尝试了stubing request.getAsync(因为bluebird将“Async”附加到promisified函数),但这也不起作用。有什么想法吗?

4 个答案:

答案 0 :(得分:5)

Promise.promisify不会修改对象,只需要一个函数并返回一个新函数,它完全不知道该函数甚至属于"request"

使用promisify时,

"Async"后缀方法会添加到对象中全部

Promise.promisifyAll(require("request"));

request.getAsync = sinon.stub()
        .yields(null, null, {error: "test error", error_description: "fake google error."});

expect(request.getAsync).to.have.been.calledOnce();

答案 1 :(得分:2)

仅供参考,我以不同的方式解决了这个问题,并且我认为更干净一些。这是打字稿,但基本相同。

fileBeingTested.ts

import * as Bluebird from 'bluebird';
import * as needsPromise from 'needs-promise';

const methodAsync = Bluebird.promisify(needsPromise.method);

export function whatever() {
    methodAsync().then(...).catch(...);
}

test.spec.ts

import * as needsPromise from 'needs-promise';
import * as sinon form 'sinon';

const methodStub = sinon.stub(needsPromise, method);
import { whatever } from './fileBeingTested';

然后,您使用methodStub管理发生的呼叫。您可以忽略它是被承诺的,而只是管理它的正常行为。例如,如果您需要它来出错。

methodStub.callsFake((arg, callback) => {
    callback({ error: 'Error' }, []);
});

承诺的版本将引发错误,您将发现错误。

答案 2 :(得分:0)

任何人遇到这个。我有小实用程序功能

from flask import Flask
from flask import jsonify
from flask import request
from flask import send_file
from flask_cors import CORS, cross_origin

app = Flask(__name__)
CORS(app)

@app.route('/get_image', methods=['GET'])
def get_image():
    return send_file('./cache/test.jpg', mimetype='image/jpeg')

在测试中

function stubCBForPromisify(stub) {
  let cbFn = function() {
    let args = [...arguments];
    args.shift();
    return stub(...args);
  };
  return cbFn.bind(cbFn, () => ({}));
}

答案 3 :(得分:0)

我在使用tapeproxyquire对此进行测试时遇到了麻烦。我不确定人们使用哪种模式/框架,允许他们直接修改required' d request对象,如接受的答案中所示。在我的情况下,在我要测试的文件require('jsonFile')中,然后调用bluebird.promisifyAll(jsonFile)。在正常情况下,这会创建一个我想要存根的readFileAsync方法。但是,如果在测试期间我尝试使用proxyquire传递存根,则对promisifyAll的调用会覆盖我的存根。

我能够通过将promisifyAll存根为无操作来解决这个问题。如图所示,如果您依赖某些async方法按原样创建,则可能过于粗糙。

core.js

var jsonFile = require('jsonfile');
var Promise = require('bluebird');
Promise.promisifyAll(jsonFile);

exports.getFile = function(path) {
  // I want to stub this method during tests. It is
  // created by promisifyAll
  return jsonFile.readFileAsync(path);
}

core-test.js

var proxyquire = require('proxyquire');
var tape = require('tape');
var sinon = require('sinon');
require('sinon-as-promised');

tape('stub readFileAsync', function(t) {
  var core = proxyquire('./core', {
    'jsonfile': {
      readFileAsync: sinon.stub().resolves({})
    },
    'bluebird': { promisifyAll: function() {} }
  });
  // Now core.getFile() will use my stubbed function, and it
  // won't be overwritten by promisifyAll.
});