【问题标题】:Stubbing api call in rails controller with RSPEC and ROR使用 RSPEC 和 ROR 在 rails 控制器中存根 api 调用
【发布时间】:2021-08-31 18:42:18
【问题描述】:

我有以下导轨控制器

class FoodsController < ApplicationController
  before_action :set_food, only: [:show, :update, :destroy]


  # GET /foods/1
  def show
   
    #render json: @food
    render json: 
    {
      "barcode": @food.barcode,
      "product": @food.product
    }
  
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_food
      #@food = Food.find(params[:id])
      
      code = params[:id]
      product = Openfoodfacts::Product.get(code, locale: 'fr')
      @food = Food.create_with(product: product.product_name).find_or_create_by(barcode: code)
    end

    # Only allow a list of trusted parameters through.
    def food_params
      params.require(:food).permit(:barcode, :product)
    end
end

我有以下 rspec 测试

require 'rails_helper'

RSpec.describe FoodsController, type: :request do
  include_context 'openfood_context'

  let(:headers) { { Authorization: "Token #{TokenAuth::API_TOKEN}" } }
  let(:response_body) { JSON.parse(response.body) }
  let(:given_product) { response_body['product'] }
  let(:given_barcode) { response_body['barcode'] }

 
  before do
    get food_path(id: barcode), headers: headers
    expect(response).to have_http_status(:ok)
    
  end

  it 'returns the product name' do
    
    expect(given_product).to eq product
  end

  it 'returns the barcode' do
    expect(given_barcode).to eq barcode
  end
end

页面有效,当我点击 foods/099482476885 路线时,我得到这张图片中的输出enter image description here。但是当我运行规范时,我得到下面的错误

1) FoodsController returns the product name
     Failure/Error: product = Openfoodfacts::Product.get(code, locale: 'fr')
     
     WebMock::NetConnectNotAllowedError:
       Real HTTP connections are disabled. Unregistered request: GET https://fr.openfoodfacts.org/api/v0/produit/049000061017.json with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}
     
       You can stub this request with the following snippet:
     
       stub_request(:get, "https://fr.openfoodfacts.org/api/v0/produit/049000061017.json").
         with(
           headers: {
          'Accept'=>'*/*',
          'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
          'User-Agent'=>'Ruby'
           }).
         to_return(status: 200, body: "", headers: {})
     
       ============================================================
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/net_http.rb:114:in `request'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/net_http.rb:123:in `start_without_connect'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/webmock-3.13.0/lib/webmock/http_lib_adapters/net_http.rb:150:in `start'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/openfoodfacts-0.6.0/lib/openfoodfacts/product.rb:25:in `get'
     # ./app/controllers/foods_controller.rb:23:in `set_food'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-2.2.3/lib/rack/etag.rb:27:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-2.2.3/lib/rack/conditional_get.rb:27:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-2.2.3/lib/rack/head.rb:12:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.1.3.2/lib/rails/rack/logger.rb:37:in `call_app'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.1.3.2/lib/rails/rack/logger.rb:26:in `block in call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.1.3.2/lib/rails/rack/logger.rb:26:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-2.2.3/lib/rack/runtime.rb:22:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-2.2.3/lib/rack/sendfile.rb:110:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.1.3.2/lib/rails/engine.rb:539:in `call'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-test-1.1.0/lib/rack/mock_session.rb:29:in `request'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-test-1.1.0/lib/rack/test.rb:266:in `process_request'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-test-1.1.0/lib/rack/test.rb:119:in `request'
     # ./spec/requests/foods_controller_spec.rb:13:in `block (2 levels) in <top (required)>'
     # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/webmock-3.13.0/lib/webmock/rspec.rb:37:in `block (2 levels) in <top (required)>'

然后我尝试将以下存根添加到 spec/spec_helper.rb,但收到与图片中类似的错误。我该如何解决这个规范问题?

 config.before(:each) do
    stub_request(:get, /api.openfoodfacts.org/).
      with(headers: {
        'Accept'=>'*/*', 
        'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
        'User-Agent'=>'Ruby'}).
      to_return(status: 200, body: "stubbed response", headers: {})
  end

【问题讨论】:

  • 一个明显的问题是您的存根正则表达式中的主机是api.openfoodfacts.org,但在错误消息中,GET 似乎命中fr.openfoodfacts.org,因此您的存根不匹配。如果您仍然有问题,请尝试从存根中删除标头,以确保首先一切正常。
  • 另外,请不要发布错误/堆栈跟踪的屏幕截图。只需将(相关)文本复制到您的问题中即可。如果错误文本不是单独的图像,那么发现问题会容易 10 倍。
  • 当我将 sub 中的主机从 api.openfoodfacts.org 更改为 fr.openfoodfacts.org 我得到 ``` FoodsController 返回产品名称失败/错误:product = Openfoodfacts::Product.get (代码,语言环境:'fr') JSON::ParserError: 767: unexpected token at '' # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/openfoodfacts-0.6.0/lib/openfoodfacts/ product.rb:26:in get' # ./app/controllers/foods_controller.rb:23:in set_food' # /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/rack-2.2.3/lib/rack/etag.rb:27:in `` `
  • 您收到 JSON 解析错误,所以我认为您的原始问题已解决,问题可能是您的存根返回的 JSON(“存根正文”?)导致您的 Openfoodfacts东西消化不良。如果您确保存根是一个有效的示例响应,它可能会变得更好。
  • 服务有可能被调用两次。可能你需要模拟两个 enpoint。注意当你模拟一个时会发生什么变化。 (也许 api.foodfacts 会返回 301 重定向到 fr.foodfacts?)

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


【解决方案1】:

您正在对api.openfoodfacts.org 的请求存根,但您分享了一个错误,抱怨向fr.openfoodfacts.org 发出的请求。

Webmock 将阻止您规范中的所有外部请求(这是设计使然),因此当您将请求存根到 foo 时,如果错误消息更改为 Unregistered request: bar,请格外注意。你需要把它们全部存根,

mock Openfoodfacts::Product 本身:

allow(Openfoodfacts::Product).to receive(:get).and_return(...)

(这将取消禁用此类的“正常”行为,并且任何调用都会返回您告诉它返回的内容。

第三种选择可能是使用VCR gem,它可以记录请求和响应,然后为您模拟它们。

每个解决方案都有其优点和缺点,(我认为)超出了这个问题的范围。

【讨论】:

    猜你喜欢
    • 2013-07-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2011-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多