我试图使用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;
答案 0 :(得分:18)
执行此操作时:
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 = { ... }
测试中的存根版本对控制器的版本没有影响。
<强> SO .... 强>
您需要将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'
答案 1 :(得分:6)
您似乎正在尝试在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 :(得分: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尝试找出问题所在。
答案 3 :(得分:1)
基于@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对象传递给相关对象的构造函数。这将允许在测试套件中插入存根。