【问题标题】:Ruby stubbing with faraday, can't get it to work法拉第的红宝石存根,无法让它工作
【发布时间】:2014-03-29 19:25:32
【问题描述】:

对不起标题,我太沮丧了,现在想不出更好的东西。

我有一个类Judge,它有一个方法#stats。这个 stats 方法应该向 api 发送一个 GET 请求并获取一些数据作为响应。我正在尝试对此进行测试并存根 stats 方法,以便我不执行实际请求。这是我的测试的样子:

describe Judge do
  describe '.stats' do

    context 'when success' do
      subject { Judge.stats }

      it 'returns stats' do
        allow(Faraday).to receive(:get).and_return('some data')

        expect(subject.status).to eq 200
        expect(subject).to be_success
      end
    end
  end
end

这是我正在测试的课程:

class Judge

  def self.stats
    Faraday.get "some-domain-dot-com/stats"
  end

end

目前这给了我错误:Faraday does not implement: get 那么你如何用法拉​​第存根呢?我见过这样的方法:

    stubs = Faraday::Adapter::Test::Stubs.new do |stub|
      stub.get('http://stats-api.com') { [200, {}, 'Lorem ipsum'] }
    end

但我似乎无法以正确的方式应用它。我在这里错过了什么?

【问题讨论】:

  • Faraday 没有收到 :get,它返回的 Faraday::Connection 实例收到了。您需要存根 Faraday 以在收到 Faraday::Connection 时返回一个实例 double :new

标签: ruby testing request stubbing faraday


【解决方案1】:

Faraday 类没有get 方法,只有实例有。由于您在类方法中使用它,因此您可以执行以下操作:

class Judge
  def self.stats
    connection.get "some-domain-dot-com/stats"
  end

  def self.connection=(val)
    @connection = val
  end

  def self.connection
    @connection ||= Faraday.new(some stuff to build up connection)
  end
end

那么在你的测试中你可以设置一个双精度:

let(:connection) { double :connection, get: nil }
before do
  allow(connection).to receive(:get).with("some-domain-dot-com/stats").and_return('some data')
  Judge.connection = connection
end

【讨论】:

  • 这看起来很整洁。得到“双重:连接收到意外消息:带有(:get)的存根”,tho。 :stub 方法和 :get 哪个是出乎意料的? :s
  • 您使用的是什么版本的 rspec?您使用的是 rspec 模拟还是其他一些模拟库?
  • rspec:3.0.0.beta2,WebMock:1.17.3
  • "Faraday 类没有get 方法" Faraday.get 是使用默认堆栈的快捷方式。但是,该堆栈不包含任何存根,这就是请求不被存根的原因。 github.com/lostisland/faraday#usage
  • (顺便说一句,我不知道"Faraday does not implement: get" 来自哪里。它不是NoMethodError。)
【解决方案2】:

Faraday::Adapter::Test::Stubs 与 Faraday does not implement: get 出错时遇到了同样的问题。看来您需要将stubs 设置为法拉第适配器,如下所示:

  stubs = Faraday::Adapter::Test::Stubs.new do |stub|
    stub.get("some-domain-dot-com/stats") { |env| [200, {}, 'egg'] }
  end

  test = Faraday.new do |builder|
    builder.adapter :test, stubs
  end

  allow(Faraday).to receive(:new).and_return(test)

  expect(Judge.stats.body).to eq "egg"
  expect(Judge.stats.status).to eq 200

【讨论】:

    【解决方案3】:

    请注意,Faraday.new 返回的是 Faraday::Connection 的实例,而不是 Faraday。所以你可以尝试使用

    allow_any_instance_of(Faraday::Connection).to receive(:get).and_return("some data")
    

    请注意,我不知道您的问题中显示的返回“一些数据”是否正确,因为 Faraday::Connection.get 应该返回一个响应对象,其中包括正文和状态代码而不是字符串。你可以试试这样的:

    allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(
       double("response", status: 200, body: "some data")
    )
    

    这是一个 Rails 控制台,显示您从 Faraday.new 返回的课程

    $ rails c
    Loading development environment (Rails 4.1.5)
    2.1.2 :001 > fara = Faraday.new
     => #<Faraday::Connection:0x0000010abcdd28 @parallel_manager=nil, @headers={"User-Agent"=>"Faraday v0.9.1"}, @params={}, @options=#<Faraday::RequestOptions (empty)>, @ssl=#<Faraday::SSLOptions (empty)>, @default_parallel_manager=nil, @builder=#<Faraday::RackBuilder:0x0000010abcd990 @handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]>, @url_prefix=#<URI::HTTP:0x0000010abcd378 URL:http:/>, @proxy=nil>
    2.1.2 :002 > fara.class
     => Faraday::Connection
    

    【讨论】:

    • 这可行,但使用allow_any_instance_of 存根是非常危险的;如果 Faraday 客户端(Faraday::Connection 实例)发出 any GET 请求,这将导致通过测试——不一定是您正在测试的请求。将 Faraday.new 存根以返回 Faraday::Connection 的实例双精度并且仅使用 receive 和 with 来验证您正在使用的参数的正确性会更安全。
    【解决方案4】:

    这么晚了,但万一其他人也是,这对我有用 - 上述方法的组合:

      let(:json_data) { File.read Rails.root.join("..", "fixtures", "ror", "501100000267.json") }
    
      before do
        allow_any_instance_of(Faraday::Connection).to receive(:get).and_return(
          double(Faraday::Response, status: 200, body: json_data, success?: true)
        )
      end
    

    【讨论】:

    • 这对我很有帮助。谢谢
    【解决方案5】:

    比使用allow_any_instance_of 更好的方法是为法拉第设置默认连接,以便Faraday.get 将使用您在测试中设置的连接。

    例如:

      let(:stubs) { Faraday::Adapter::Test::Stubs.new }
      let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
    
      before do
        stubs.get('/maps/api/place/details/json') do |_env|
          [
            200,
            { 'Content-Type': 'application/json' },
            { 'result' => { 'photos' => [] } }.to_json
          ]
        end
    
        Faraday.default_connection = conn
      end
    
      after do
        Faraday.default_connection = nil
      end
    

    【讨论】:

      猜你喜欢
      • 2017-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-10
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多