web-dev-qa-db-ja.com

RspecのデフォルトのGET要求形式をJSONに設定します

Rspecでコントローラーの機能テストを行っています。ルーターのデフォルトの応答形式をJSONに設定しているため、接尾辞のないすべての要求はJSONを返します。

今RSpecでは、私がしようとするとエラー(406)が表示されます

get :index

する必要があります

get :index, :format => :json

現在、私は主にAPIでJSONをサポートしているため、すべてのリクエストにJSON形式を指定することは非常に冗長です。

すべてのGETリクエストに対して何らかの方法でデフォルトに設定できますか? (またはすべてのリクエスト)

47
Drazen Mokic
before :each do
  request.env["HTTP_ACCEPT"] = 'application/json'
end
50
Pratik Khadloya

これをspec/supportに入れます:

require 'active_support/concern'

module DefaultParams
  extend ActiveSupport::Concern

  def process_with_default_params(action, parameters, session, flash, method)
    process_without_default_params(action, default_params.merge(parameters || {}), session, flash, method)
  end

  included do
    let(:default_params) { {} }
    alias_method_chain :process, :default_params
  end
end

RSpec.configure do |config|
  config.include(DefaultParams, :type => :controller)
end

そして、単にdefault_paramsをオーバーライドします:

describe FooController do
    let(:default_params) { {format: :json} }
    ...
end
24
knoopx

次はrspecで動作します:

before :each do
  request.headers["accept"] = 'application/json'
end

これにより、HTTP_ACCEPT

16
schmijos

ここに解決策があります

  1. リクエスト仕様に対応、
  2. Rails 5、および
  3. Rails(processなど)のプライベートAPIは含まれません。

RSpec設定は次のとおりです。

module DefaultFormat
  extend ActiveSupport::Concern

  included do
    let(:default_format) { 'application/json' }
    prepend RequestHelpersCustomized
  end

  module RequestHelpersCustomized
    l = lambda do |path, **kwarg|
      kwarg[:headers] = {accept: default_format}.merge(kwarg[:headers] || {})
      super(path, **kwarg)
    end
    %w(get post patch put delete).each do |method|
      define_method(method, l)
    end
  end
end

RSpec.configure do |config|
  config.include DefaultFormat, type: :request
end

検証済み

describe 'the response format', type: :request do
  it 'can be overridden in request' do
    get some_path, headers: {accept: 'text/plain'}
    expect(response.content_type).to eq('text/plain')
  end

  context 'with default format set as HTML' do
    let(:default_format) { 'text/html' }

    it 'is HTML in the context' do
      get some_path
      expect(response.content_type).to eq('text/html')
    end
  end
end

FWIW、RSpec構成を配置できます。

  1. spec/spec_helper.rbで直接。これは推奨されません。 lib/でライブラリメソッドをテストする場合でも、ファイルはロードされます。

  2. spec/Rails_helper.rbで直接。

  3. (私のお気に入り)spec/support/default_format.rbで、spec/Rails_helper.rbで明示的にロードされます

    require 'support/default_format'
    
  4. spec/supportで、によってロードされる

    Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
    

    spec/supportのすべてのファイルをロードします。

このソリューションは knoopxの答え に触発されています。彼のソリューションはリクエスト仕様では機能せず、 alias_method_chain は推奨されなくなり、 Module#prepend

11
Franklin Yu

RSpec 3では、ビューをレンダリングさせるためにJSONテストをリクエスト仕様にする必要があります。私が使用するものは次のとおりです。

# spec/requests/companies_spec.rb
require 'Rails_helper'

RSpec.describe "Companies", :type => :request do
  let(:valid_session) { {} }

  describe "JSON" do
    it "serves multiple companies as JSON" do
      FactoryGirl.create_list(:company, 3)
      get 'companies', { :format => :json }, valid_session
      expect(response.status).to be(200)
      expect(JSON.parse(response.body).length).to eq(3) 
    end

    it "serves JSON with correct name field" do
      company = FactoryGirl.create(:company, name: "Jane Doe")
      get 'companies/' + company.to_param, { :format => :json }, valid_session
      expect(response.status).to be(200)
      expect(JSON.parse(response.body)['name']).to eq("Jane Doe")
    end
  end
end

すべてのテストで形式を設定することに関して、私はこの他の答えからのアプローチが好きです: https://stackoverflow.com/a/14623960/1935918

7
Dan Kohn

おそらく、これを使って最初の回答をspec/spec_helperまたはspec/Rails_helperに追加できます。

config.before(:each) do
  request.env["HTTP_ACCEPT"] = 'application/json' if defined? request
end

モデルテスト(または存在しないリクエストメソッドコンテキスト)の場合、このコードは無視します。 rspec 3.1.7およびRails 4.1.0で動作しました。すべてのRails 4バージョンで一般的に動作します。

6
zw963

Rails 5およびRspec 3.5を実行すると、これを実現するためにヘッダーを設定する必要がありました。

post '/users', {'body' => 'params'}, {'ACCEPT' => 'application/json'}

Thiは、 docs の例がどのように見えるかと一致します。

require "Rails_helper"

RSpec.describe "Widget management", :type => :request do
  it "creates a Widget" do
    headers = {
      "ACCEPT" => "application/json",     # This is what Rails 4 accepts
      "HTTP_ACCEPT" => "application/json" # This is what Rails 3 accepts
    }
    post "/widgets", { :widget => {:name => "My Widget"} }, headers

    expect(response.content_type).to eq("application/json")
    expect(response).to have_http_status(:created)
  end
end
2
settheline

リクエストテストで作業する人にとって、私が見つけた最も簡単な方法は、#processActionDispatch::Integration::Sessionメソッドをオーバーライドし、デフォルトのasパラメーターを:jsonに設定することです。

module DefaultAsForProcess
  def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: :json)
    super
  end
end

ActionDispatch::Integration::Session.prepend(DefaultAsForProcess)
1
mpospelov

Rspec docs に従って、サポートされている方法はヘッダーを介したものです。

require "Rails_helper"

RSpec.describe "Widget management", :type => :request do

  it "creates a Widget" do
    headers = {
      "ACCEPT" => "application/json",      # This is what Rails 4 and 5 accepts
      "HTTP_ACCEPT" => "application/json", # This is what Rails 3 accepts
    }
    post "/widgets", :params => { :widget => {:name => "My Widget"} }, :headers => headers

    expect(response.content_type).to eq("application/json")
    expect(response).to have_http_status(:created)
  end

end
0
DBrown