将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
- 适用于请求规格,
- 与Rails 5一起工作
- 不涉及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:
-
直接在
spec/spec_helper.rb
。 这不是build议; 即使在lib/
testing库方法时,该文件也会被加载。 -
直接在
spec/rails_helper.rb
。 -
(我最喜欢的)在
spec/support/default_format.rb
,并在spec/rails_helper.rb
明确加载require 'support/default_format'
-
在
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