【问题标题】:How to test if a class receives a message in RSpec?如何测试一个类是否在 RSpec 中收到消息?
【发布时间】:2016-03-08 16:26:05
【问题描述】:

我有一个类似的服务对象:

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

如何测试这种行为?

【问题讨论】:

  • 移动service.call之前的期望。
  • @DaveSchweisguth 您可以将其添加为答案以便我批准吗?谢谢

标签: ruby-on-rails ruby rspec rspec-rails rspec-mocks


【解决方案1】:

您需要在调用方法之前设置模拟。 RSpec 提供了两种方法来做到这一点:

  1. 移动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
    
  2. 通过allowing 将要调用的方法设置为间谍,然后期望它在事后被调用:

    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
    

如您所见,第一种方法需要最少的输入,但需要提前思考。第二种方法更冗长,但更合乎逻辑,因为它将期望放在方法调用之后。

【讨论】:

    猜你喜欢
    • 2018-05-27
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2016-01-12
    • 1970-01-01
    • 2013-01-19
    相关资源
    最近更新 更多