用sinon绑定条纹 - 使用stub.yields

问题描述 投票:6回答:4

我试图用sinon将nodejs stripe api存根,用一个看起来像这样的测试来测试客户的创建:

var sinon = require('sinon');
var stripe = require('stripe');
var controller = require('../my-controller');

var stub = sinon.stub(stripe.customers, 'create');
stub.create.yields([null, {id: 'xyz789'}]);
//stub.create.yields(null, {id: 'xyz789'}); //same result with or without array 

controller.post(req, {}, done);

我的理解是stub.create.yields应该调用第一个回调,并传递它(在本例中)为null,然后是一个id为xyz789的对象。这可能是我错的地方

在我的'控制器'里面我有以下内容:

exports.post = function(req, res, next) {

    stripe.customers.create({
        card: req.body.stripeToken,
        plan: 'standard1month',
        email: req.body.email
    }, function(err, customer) {

        console.log('ERR = ', err)
        console.log('CUSTOMER = ', customer)

错误,客户都是未定义的。

我做错了什么吗?

编辑

我认为这个问题可以在这里:(条纹文档)

var stripe = require('stripe')(' your stripe API key ');

所以,stripe构造函数采用api密钥

在我的测试中,我不提供一个:var stripe = require('stripe');

但在我的控制器中,我有:

var stripe = require('stripe')('my-key-from-config');

所以,根据你的例子,我有:

test.js:

var controller = require('./controller');
var sinon = require('sinon');
var stripe = require('stripe')('test');

var stub = sinon.stub(stripe.customers, 'create');
stub.yields(null, {id: 'xyz789'});
//stub.create.yields(null, {id: 'xyz789'}); //same result with or without array 

controller.post({}, {}, function(){});

controller.js

var stripe = require('stripe')('my-key-from-config');

var controller = {
    post: function (req, res, done) {
        stripe.customers.create({
            card: req.body,
            plan: 'standard1month',
        }, function(err, customer) {
            console.log('ERR = ', err);
            console.log('CUSTOMER = ', customer);
        });
    }
}

module.exports = controller;
javascript node.js sinon
4个回答
19
投票

当你这样做:

var stripe = require('stripe')('my-key-from-config');

条带库动态创建customer和其他对象。所以,当你在一个文件中存根时:

test.js

var stripe = require('stripe')('test');
var stub = sinon.stub(stripe.customers, 'create');

并且您的控制器创建另一个stripe实例以在另一个文件中使用:

controller.js

var stripe = require('stripe')('my-key-from-config');
var controller = { ... }

测试中的存根版本对控制器的版本没有影响。

所以....

您需要将stripe的测试实例注入您的控制器,或者使用像nock这样的库来模拟http级别的内容,如下所示:

  nock('https://api.stripe.com:443')
    .post('/v1/customers', "email=user1%40example.com&card=tok_5I6lor706YkUbj")
    .reply 200, 
      object: 'customer'  
      id: 'cus_somestripeid'

7
投票

看起来你正在尝试在Stripe API中将#post.cteomers.create()中的#post()函数隔离开来。 @lambinator指出客户对象是在您调用时动态创建的

require('stripe')('my-key-from-config')

require('stripe')('test')

所以你的存根在测试中不适用于控制器中的#stripe.customers.create()。

您可以将条带的测试实例注入控制器,如@lambinator建议的那样。注射几乎是最好的。但是,如果您正在编写橡胶符合道路类型的组件(如代理),则注射是不合适的。相反,您可以使用Stripe模块中提供的第二个导出:

Stripe.js:

...

// expose constructor as a named property to enable mocking with Sinon.JS
module.exports.Stripe = Stripe;

测试:

var sinon = require('sinon');
var stripe = require('stripe')('test');
var StripeObjectStub = sinon.stub(Stripe, 'Stripe', function(){
  return stripe;
});
//NOTE! This is required AFTER we've stubbed the constructor.
var controller = require('./controller');

var stub = sinon.stub(stripe.customers, 'create');
stub.create.yields([null, {id: 'xyz789'}]);
//stub.create.yields(null, {id: 'xyz789'}); //same result with or without array 

controller.post({}, {}, function(){});

控制器:

require('stripe').Stripe('my-key-from-config');

var controller = {
post: function (req, res, done) {
    stripe.customers.create({
        card: req.body,
        plan: 'standard1month',
    }, function(err, customer) {
        console.log('ERR = ', err);
        console.log('CUSTOMER = ', customer);
    });
}

然后,在你的控制器中,#stripe.customers.create()将调用你的测试存根。


2
投票

它可能不属于您在此处描述的内容。

yields is an alias for callsArg,但尝试call the first argument that is a function并提供arguments using Function.prototype.apply - 这意味着@psquared说它不需要是一个数组是正确的。

但是,这不是你的问题。试图在JSFiddle, we can see that it successfully calls back the argument中重新创建给定的代码。

var stripe = {
    customers: {
        create: function () {}
    }
};
var controller = {
    post: function (req, res, done) {
        stripe.customers.create({
            card: req.body,
            plan: 'standard1month',
        }, function(err, customer) {
            console.log('ERR = ', err);
            console.log('CUSTOMER = ', customer);
        });
    }
}

var stub = sinon.stub(stripe.customers, 'create');
stub.yields(null, {id: 'xyz789'});
//stub.create.yields(null, {id: 'xyz789'}); //same result with or without array 

controller.post({}, {}, function(){});

这告诉我你需要显示更多代码,或者尝试使用writing a reduced test case来尝试找出问题所在。


2
投票

基于@ Angrysheep的答案,该答案使用导出的Stripe构造函数(最好的方法IMHO),这是编写本文时的工作代码:

调节器

//I'm using dotenv to get the secret key
var stripe = require('stripe').Stripe(process.env.STRIPE_SECRET_KEY);

测试

//First, create a stripe object
var StripeLib = require("stripe");
var stripe = StripeLib.Stripe('test');

//Then, stub the stripe library to always return the same object when calling the constructor
const StripeStub = sinon.stub(StripeLib, 'Stripe').returns(stripe);

// import controller here. The stripe object created there will be the one create above
var controller = require('./controller');

 describe('a test', () => {
     let createCustomerStub;
     const stripeCustomerId = 'a1b2c3';

     before(() => {
        //Now, when we stub the object created here, we also stub the object used in the controller
        createCustomerStub = sinon.stub(stripe.customers, 'create').returns({id: stripeCustomerId});
    });

    after(() => {   
        createCustomerStub.restore();
    });
});

编辑:根据下面的评论,这种方法可能不再有效。

绕过整个问题的合理方法是使用Stripe作为注入依赖项,即将Stripe对象传递给相关对象的构造函数。这将允许注入存根作为测试套件的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.