我试图用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;
当你这样做:
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'
看起来你正在尝试在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()将调用你的测试存根。
它可能不属于您在此处描述的内容。
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来尝试找出问题所在。
基于@ 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对象传递给相关对象的构造函数。这将允许注入存根作为测试套件的一部分。