我使用Rails 5和Rspec 3.如何在Rspec方法中模拟一个类?我有以下课程
require 'rails_helper'
describe CryptoCurrencyService do
describe ".sell" do
it "basic_sell" do
last_buy_price = 3000
last_transaction = MoneyMakerTransaction.new({
:transaction_type => "buy",
:amount_in_usd => "100",
:btc_price_in_usd => "#{last_buy_price}"
})
@client = Coinbase::Wallet::Client.new(api_key: ENV['COINBASE_KEY'], api_secret: ENV['COINBASE_SECRET'])
sell_price = 4000
assert sell_price > last_buy_price * (1 + MoneyMakerThreshhold.find_buy.pct_change)
allow(@client).to receive(:sell_price).and_return({"base"=>"BTC", "currency"=>"USD", "amount"=>"#{sell_price}"})
svc = CryptoCurrencyService.new
svc.sell(last_transaction)
last_transaction = MoneyMakerTransaction.find_latest_record
assert last_transaction.transaction_type, "sell"
end
end
end
而不是实际实例化类" Coinbase :: Wallet"在行
@client = Coinbase::Wallet::Client.new(api_key: ENV['COINBASE_KEY'], api_secret: ENV['COINBASE_SECRET'])
我想创建mock taht然后我可以插入我的服务类,我正在测试。就目前而言,当我运行时,实际的底层类被实例化,导致运行时错误......
1) CryptoCurrencyService.sell basic_sell
Failure/Error: payment_method = client.payment_methods()[0]
Coinbase::Wallet::AuthenticationError:
invalid api key
答案 0 :(得分:7)
rspec模拟和存根可以在任何类上使用。 例如:
coinbase_mock = double(api_key: ENV['COINBASE_KEY'], api_secret: ENV['COINBASE_SECRET'])
expect(Coinbase::Wallet::Client).to_receive(:new).and_return(coinbase_mock)
然后你可以添加你喜欢的任何内容到coinbase_mock
,这样它就像你需要的类一样嘎嘎...:)
答案 1 :(得分:2)
您可以像这样使用Ruby Struct:
Coinbase::Wallet::Client = Struct.new(:api_key, :api_secret)
@client = Coinbase::Wallet::Client.new(ENV['COINBASE_KEY'], ENV['COINBASE_SECRET'])
@client.api_key #=> whatever was in ENV['COINBASE_KEY']
然后传入该对象。
如果你需要行为,你也可以这样:
Coinbase::Wallet::Client = Struct.new(:api_key, :api_secret) do
def client_info
## logic here
"info"
end
end
@client = Coinbase::Wallet::Client.new(ENV['COINBASE_KEY'], ENV['COINBASE_SECRET'])
@client.client_info #=> "info"
答案 2 :(得分:1)
首选RSpec(自第3版以来)风格为
let(:coinbase_client) { instance_double(Coinbase::Wallet::Client) }
# validates that mocked/stubbed methods present in class definitiion
before do
allow(coinbase_client).to receive(:sell_price).and_return({"base"=>"BTC", "currency"=>"USD", "amount"=>"PRICE YOU PROVIDE"})
end
docs about instance_double method
将coinbase_client作为构造参数注入到内部使用它的类
或者如果由于某些原因你不能使用依赖注入,你可以使用
模拟任何Coinbase :: Wallet :: Client的实例allow_any_instance_of(Coinbase::Wallet::Client).to receive(... *mock specific method*)