将Rspec默认GET请求格式设置为JSON

我正在使用Rspec为我的控制器进行functiontesting。 我已经在我的路由器中将默认响应格式设置为JSON,因此每个没有后缀的请求都将返回JSON。

现在在rspec中,当我尝试时,出现错误(406)

get :index 

我需要去做

 get :index, :format => :json 

现在因为我主要用API来支持JSON,所以为每个请求指定JSON格式是非常多余的。

我可以以某种方式将其设置为默认的所有我的GET请求? (或所有请求)

 before :each do request.env["HTTP_ACCEPT"] = 'application/json' end 

把它放在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 

下面的rspec 3适用于我:

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

这设置了HTTP_ACCEPT

在RSpec 3中,您需要使JSONtesting成为请求规范以便呈现视图。 这是我使用的:

 # 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 

至于设置所有testing的格式,我喜欢从这个其他答案的方法: https : //stackoverflow.com/a/14623960/1935918

这是一个解决scheme

  1. 适用于请求规格,
  2. 与Rails 5一起工作
  3. 不涉及Rails的私有API(如process )。

这是RSpecconfiguration:

 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 

通过validation

 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,可以放置RSpecconfiguration:

  1. 直接在spec/spec_helper.rb 。 这不是build议; 即使在lib/testing库方法时,该文件也会被加载。

  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所有文件。

这个解决scheme受到了Knoopx的回答 。 他的解决scheme不适用于请求规范, alias_method_chain已被弃用,以支持Module#prepend

也许你可以添加第一个答案到spec / spec_helper或spec / rails_helper中:

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

如果在模型testing(或任何不存在的请求方法上下文)中,这个代码只是忽略。 它与rspec 3.1.7和rails 4.1.0一起工作,它应该与所有rails 4版本一般来说。

运行Rails 5和Rspec 3.5我必须设置标题来完成这个。

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

Thi与文档中的示例相匹配:

 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 

对于那些使用请求testing的人来说,我发现的最简单的方法是重写ActionDispatch::Integration::Session #process方法,并将默认参数设置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) 

为什么RSpec的方法,“get”,“post”,“put”,“delete”在gem(或Rails之外)的控制器规范中工作?

基于这个问题,你可以尝试从https://github.com/rails/rails/blob/32395899d7c97f69b508b7d7f9b7711f28586679/actionpack/lib/action_controller/test_case.rb在ActionController :: TestCase中重新定义process()。

这是我的解决方法。

 describe FooController do let(:defaults) { {format: :json} } context 'GET index' do let(:params) { defaults } before :each do get :index, params end # ... end context 'POST create' do let(:params) { defaults.merge({ name: 'bar' }) } before :each do post :create, params end # ... end end