如何测试 class 是否收到 RSpec 中的消息?
How to test if a class receives a message in RSpec?
我有一个类似这样的服务对象:
class SecurityQueryService
class Contract::NotFound < StandardError; end
attr_reader :ticker_name, :contract_type, :contract
def initialize(user, params)
@user = user
@ticker_name = params[:ticker_name].upcase
@contract_type = params[:type]
end
def call
find_contract
end
private
def find_contract
@contract ||= contract_klass.find_by(ticker: ticker_name)
fail(
Contract::NotFound,
"Cannot find contract with ticker_name #{ticker_name}"
) if @contract.nil?
end
def contract_klass
return EquityContract if contract_type.nil?
"#{contract_type.strip.capitalize}Contract".constantize
end
end
我有以下相关规范:
require 'spec_helper'
describe SecurityQueryService do
let(:user) { create(:customer) }
let!(:equity_contract) { create(:equity_contract) }
describe "#call" do
describe "#find_contract" do
it "returns contract based on contract type." do
service = SecurityQueryService.new(user, {
type: 'equity',
ticker_name: equity_contract.ticker
})
service.call
expect(EquityContract).to receive(:find_by)
end
end
end
end
我想确保 EquityContract
在我调用 #call
时收到 find_by
消息。
在我 运行 我得到的规范的那一刻:
Failure/Error: expect(EquityContract).to receive(:find_by)
(EquityContract(id: integer, ticker: string, name: string, country: string, currency: string, instrument_type: string, bloomberg_ticker: string, benchmark_index: string, skip_valuation: boolean, isin: string, currency_factor: decimal, daily_update: boolean, id_bb_unique: string, image: string, domain: string) (class)).find_by(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
我如何测试这种行为?
您需要在调用该方法之前设置模拟。 RSpec 提供了两种方法:
把期望移到service.call
之前:
describe "#find_contract" do
it "returns contract based on contract type." do
service = SecurityQueryService.new(user,
type: 'equity',
ticker_name: equity_contract.ticker
)
expect(EquityContract).to receive(:find_by)
service.call
end
end
通过 allow
ing 要调用的方法将方法设置为间谍,然后期望它在事后被调用:
describe "#find_contract" do
it "returns contract based on contract type." do
service = SecurityQueryService.new(user,
type: 'equity',
ticker_name: equity_contract.ticker
)
allow(EquityContract).to receive(:find_by)
service.call
expect(EquityContract).to have_received(:find_by)
end
end
如您所见,第一种方法需要最少的输入,但需要笨拙的提前思考。第二种方法更冗长,但更合乎逻辑,因为它将期望放在方法调用之后。
我有一个类似这样的服务对象:
class SecurityQueryService
class Contract::NotFound < StandardError; end
attr_reader :ticker_name, :contract_type, :contract
def initialize(user, params)
@user = user
@ticker_name = params[:ticker_name].upcase
@contract_type = params[:type]
end
def call
find_contract
end
private
def find_contract
@contract ||= contract_klass.find_by(ticker: ticker_name)
fail(
Contract::NotFound,
"Cannot find contract with ticker_name #{ticker_name}"
) if @contract.nil?
end
def contract_klass
return EquityContract if contract_type.nil?
"#{contract_type.strip.capitalize}Contract".constantize
end
end
我有以下相关规范:
require 'spec_helper'
describe SecurityQueryService do
let(:user) { create(:customer) }
let!(:equity_contract) { create(:equity_contract) }
describe "#call" do
describe "#find_contract" do
it "returns contract based on contract type." do
service = SecurityQueryService.new(user, {
type: 'equity',
ticker_name: equity_contract.ticker
})
service.call
expect(EquityContract).to receive(:find_by)
end
end
end
end
我想确保 EquityContract
在我调用 #call
时收到 find_by
消息。
在我 运行 我得到的规范的那一刻:
Failure/Error: expect(EquityContract).to receive(:find_by)
(EquityContract(id: integer, ticker: string, name: string, country: string, currency: string, instrument_type: string, bloomberg_ticker: string, benchmark_index: string, skip_valuation: boolean, isin: string, currency_factor: decimal, daily_update: boolean, id_bb_unique: string, image: string, domain: string) (class)).find_by(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
我如何测试这种行为?
您需要在调用该方法之前设置模拟。 RSpec 提供了两种方法:
把期望移到
service.call
之前:describe "#find_contract" do it "returns contract based on contract type." do service = SecurityQueryService.new(user, type: 'equity', ticker_name: equity_contract.ticker ) expect(EquityContract).to receive(:find_by) service.call end end
通过
allow
ing 要调用的方法将方法设置为间谍,然后期望它在事后被调用:describe "#find_contract" do it "returns contract based on contract type." do service = SecurityQueryService.new(user, type: 'equity', ticker_name: equity_contract.ticker ) allow(EquityContract).to receive(:find_by) service.call expect(EquityContract).to have_received(:find_by) end end
如您所见,第一种方法需要最少的输入,但需要笨拙的提前思考。第二种方法更冗长,但更合乎逻辑,因为它将期望放在方法调用之后。