2014-07-18 49 views
4

我試圖在我的Rails應用中測試場景,其中客戶已允許訂閱轉到「未付款」(通常是因爲卡片已過期,並且在兩週內沒有更新,而Stripe重新嘗試收取費用),並且最終開始更新卡並重新激活帳戶。我相信我的邏輯是正確的(更新卡並支付每個未付款的發票),但我希望能夠測試它,或者更好的是編寫一些RSpec測試(功能測試和可能的控制器測試)。 問題是,我無法弄清楚如何創建一個訂閱「無償」的模擬情況。(我想我可以用過期的卡片創建一堆帳戶,等待兩週的時間來測試,但這不是一個可以接受的解決方案,我甚至不能改變訂閱重試設置僅用於'測試'上下文來加速過程)我發現stripe-ruby-mock但我無法手動設置訂閱的狀態。如何使用Ruby on Rails在Stripe中測試未付費訂閱?

這是我已經試過:

plan = Stripe::Plan.create(id: 'test') 
    customer = Stripe::Customer.create(id: 'test_customer', card: 'tk', plan: 'test') 

    sub = customer.subscriptions.retrieve(customer.subscriptions.data.first.id) 
    sub.status = 'unpaid' 
    sub.save 
    sub = customer.subscriptions.retrieve(customer.subscriptions.data.first.id) 
    expect(sub.status).to eq 'unpaid' 

這與條紋紅寶石模擬結果:

Failure/Error: expect(sub.status).to eq 'unpaid' 

    expected: "unpaid" 
     got: "active" 

回答

6

條紋推薦的程序是:

  1. 設置的客戶使用卡4000000000000341(「將此卡附加到客戶對象將會成功,但嘗試向卡充電ustomer將失敗。「)

  2. 給客戶一個訂閱,但是試用日期將在今天/明天結束。

  3. 等待

第三步是煩人,但它會完成這項工作。

+0

我害怕這一點。 –

+1

我遇到了同樣的問題,但對於第2步/ 3,以編程方式更新訂閱上的'trial_end'屬性。以編程方式進行,意味着您可以根據自己的喜好給出一個結束時間,例如, <1分鐘。像郵差這樣的東西使這非常容易。 – Bede

2

考慮@ VoteyDisciple的建議,我已經通過一些東西在RSpec中有合理的自動化(根據具體情況而定「合理」)。我使用VCR捕獲API調用(針對測試條帶環境),這是必不可少的,因爲這意味着sleep調用僅在首次記錄測試時發生。

使用註釋來指示通過Stripe的API完成的行爲,因爲我的實現在我的項目中被困住了,而且沒那麼有用。

VCR.use_cassette('retry') do |cassette| 
    # Clear out existing Stripe data: customers, coupons, plans. 
    # This is so the test is reliably repeatable. 
    Stripe::Customer.all.each &:delete 
    Stripe::Coupon.all.each &:delete 
    Stripe::Plan.all.each &:delete 

    # Create a plan, in my case it has the id 'test'. 
    Stripe::Plan.create(
    id:    'test', 
    amount:   100_00, 
    currency:  'AUD', 
    interval:  'month', 
    interval_count: 1, 
    name:   'RSpec Test' 
) 

    # Create a customer 
    customer = Stripe::Customer.create email: '[email protected]' 
    token = card_token cassette, '4000000000000341' 
    # Add the card 4000000000000341 to the customer 
    customer.sources.create token: 'TOKEN for 0341' 
    # Create a subscription with a trial ending in two seconds. 
    subscription = customer.subscriptions.create(
    plan:  'test', 
    trial_end: 2.seconds.from_now.to_i 
) 

    # Wait for Stripe to create a proper invoice. I wish this 
    # was unavoidable, but I don't think it is. 
    sleep 180 if cassette.recording? 

    # Grab the invoice that actually has a dollar value. 
    # There's an invoice for the trial, and we don't care about that. 
    invoice = customer.invoices.detect { |invoice| invoice.total > 0 } 
    # Force Stripe to attempt payment for the first time (instead 
    # of waiting for hours). 
    begin 
    invoice.pay 
    rescue Stripe::CardError 
    # Expecting this to fail. 
    end 

    invoice.refresh 
    expect(invoice.paid).to eq(false) 
    expect(invoice.attempted).to eq(true) 

    # Add a new (valid) card to the customer. 
    token = card_token cassette, '4242424242424242' 
    card = customer.sources.create token: token 
    # and set it as the default 
    customer.default_source = card.id 
    customer.save 

    # Run the code in your app that retries the payment, which 
    # essentially invokes invoice.pay again. 
    # THIS IS FOR YOU TO IMPLEMENT 

    # And now we can check that the invoice wass successfully paid 
    invoice.refresh 
    expect(invoice.paid).to eq(true) 
end 

以自動化方式獲取卡令​​牌是一個全新的複雜領域。什麼我有可能不爲別人打工,但這裏的紅寶石方法,呼喚phantomjs(你需要通過發送VCR中的對象):

def card_token(cassette, card = '4242424242424242') 
    return 'tok_my_default_test_token' unless cassette.recording? 

    token = `phantomjs --ignore-ssl-errors=true --ssl-protocol=any ./spec/fixtures/stripe_tokens.js #{ENV['STRIPE_PUBLISH_KEY']} #{card}`.strip 
    raise "Unexpected token: #{token}" unless token[/^tok_/] 

    token 
end 

這phantomjs運行JavaScript文件(stripe_tokens.js)包含:

var page = require('webpage').create(), 
    system = require('system'); 

var key = system.args[1], 
    card = system.args[2]; 

page.onCallback = function(data) { 
    console.log(data); 
    phantom.exit(); 
}; 

page.open('spec/fixtures/stripe_tokens.html', function(status) { 
    if (status == 'success') { 
    page.evaluate(function(key, card) { 
     Stripe.setPublishableKey(key); 
     Stripe.card.createToken(
     {number: card, cvc: "123", exp_month: "12", exp_year: "2019"}, 
     function(status, response) { window.callPhantom(response.id) } 
    ); 
    }, key, card); 
    } 
}); 

最後,所涉及的HTML文件(stripe_tokens.html)很簡單:

<html> 
    <head> 
    <script type="text/javascript" src="https://js.stripe.com/v2/"></script> 
    </head> 
    <body></body> 
</html> 

把所有的一起,並很好,它可能工作!它爲我們的應用程序:)