如何在rspec测试中跳过服务呼叫

时间:2018-09-01 06:30:44

标签: ruby-on-rails ruby rspec

我正在为此服务编写测试。

  def run
    sort_offers(product).each do |product_code|
      ......
      offer.update(poduct_params)
      Importer::Partner.get_details(product_code).new
    end
  end

它正在调用服务,在某些情况下,该服务将覆盖运行offer.update(product_prams)时保存的值。我该如何在测试中跳过服务呼叫?

这是我测试的例子

 context 'is valid' do
  .... .....
  before do
    Importer::ProductCodes(product).run
  end
  it ......
end

2 个答案:

答案 0 :(得分:0)

RSpec内置了一个非常强大的存根和模拟库(rspec mocks)。

require 'spec_helper'

module Importer
  class Partner
    def self.get_details(product_code)
      "original return value"
    end
  end
end

class FooService
  def self.run
    Importer::Partner.get_details('bar')
  end
end

RSpec.describe FooService do
  let(:partner_double) { class_double("Importer::Partner") }

  before do
    stub_const("Importer::Partner", partner_double)
    allow(partner_double).to receive(:get_details).and_return 'our mocked value'
  end

  it "creates a double for the dependency" do
    expect(FooService.run).to eq 'our mocked value'
  end
end

class_double为该类创建一个double,您可以使用.expect.allow以及模拟接口来设置返回值。这非常有用,因为您可以存根newintialize方法来返回double或spy。

stub_constant将在完成规范后将常数重置为其先前的值。

那表示您可以通过在服务中使用构造函数注入来避免使用stub_constant

class PhotoImportService

  attr_accessor :client, :username

  def initialize(username, api_client: nil)
    @username = username
    @client = api_client || APIClient.new(ENV.fetch('API_KEY'))
  end

  def run
    client.get_photos(username)
  end
end

答案 1 :(得分:0)

我将存根Importer::Partner.get_details返回一个对double做出响应的new

context 'is valid' do
  before do
    allow(Importer::Partner).to receive(:get_details).and_return(double(new: nil))
  end  

  # it ...
end

根据您的需求,您可能希望增加使用正确参数调用该模拟并且实际上也对该模拟调用了new的期望:

context 'is valid' do
  let(:mock) { double(new: nil) }

  before do
    allow(Importer::Partner).to receive(:get_details).and_return(double(new: nil))
  end  

  it "calls the service" do
    an_instance.run

    expect(Importer::Partner).to have_received(:get_details).with(
      foo: 'bar' # the arguments you would expect
    )
    expect(mock).to have_received(:new)
  end
end