在 rspec on rails 中使用模擬和存根時,我感到困惑。我有如下測驗
require 'rails_helper'
class Payment
attr_accessor :total_cents
def initialize(payment_gateway, logger)
@payment_gateway = payment_gateway
@logger = logger
end
def save
response = @payment_gateway.charge(total_cents)
@logger.record_payment(response[:payment_id])
end
end
class PaymentGateway
def charge(total_cents)
puts "THIS HITS THE PRODUCTION API AND ALTERS PRODUCTION DATA. THAT'S BAD!"
{ payment_id: rand(1000) }
end
end
class LoggerA
def record_payment(payment_id)
puts "Payment id: #{payment_id}"
end
end
describe Payment do
it 'records the payment' do
payment_gateway = double()
allow(payment_gateway).to receive(:charge).and_return(payment_id: 1234)
logger = double('LoggerA')
expect(logger).to receive(:record_payment).with(1234)
payment = Payment.new(payment_gateway, logger)
payment.total_cents = 1800
payment.save
end
end
好的,當我運行 rspec 時,它可以作業,沒問題,但是當我嘗試移動expect到如下所示的最后一行時:
payment = Payment.new(payment_gateway, logger)
payment.total_cents = 1800
payment.save
expect(logger).to receive(:record_payment).with(1234)
我嘗試運行rpsec,它失敗了,我不知道為什么expect是最后一行會失敗,我認為expect總是在我們運行某些東西以獲得測驗結果之前放在最后一行。任何人都可以為我解釋?
uj5u.com熱心網友回復:
expect(sth).to receive設定在呼叫和測驗結束之間要滿足的訊息期望,并且在測驗完成后驗證該期望。當您將 移到expect最后一行時,期望在測驗結束時設定,并且沒有執行任何代碼來滿足它,因此它失敗了。不幸的是,這意味著打破了準備-執行-測驗的順序。
這就是為什么你真的應該很少使用expect.to receive并將其替換allow.to receive為expect.to have_received
# prepare
allow(logger).to receive(:record_payment)
# execute
..
# test
expect(logger).to have_received(:record_payment).with(1234)
allow.to receive設定一個模擬代理,它開始跟蹤接收到的訊息,然后可以通過expect.to have_received. 某些物件會自動設定它們的模擬代理,例如您不需要allow.to receive具有預定義回應或spies. 在您的情況下,您可以撰寫如下測驗:
payment_gateway = double
allow(payment_gateway).to receive(:charge).and_return(payment_id: 1234)
logger = double('LoggerA', record_payment: nil)
payment = Payment.new(payment_gateway, logger)
payment.total_cents = 1800
payment.save
expect(logger).to have_received(:record_payment).with(1234)
其他注意事項
我強烈建議使用verifiable_doubles,這將保護您免受誤報:
payment_gateway = instance_double(PaymentGateway)
allow(payment_gateway).to receive(:charge).and_return(payment_id: 1234)
如果chargePaymentGateway 類上沒有定義任何方法,此測驗現在將引發例外- 即使您重命名該方法但忘記在測驗和實作中重命名它,也可以保護您免受測驗通過。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/362798.html
標籤:红宝石轨道 红宝石 规格 rspec-rails
