Вопрос по ruby-on-rails, functional-testing, rspec – Установите формат GET-запроса Rspec по умолчанию в JSON

44

Я делаю функциональные тесты для моих контроллеров с Rspec. Я установил в своем маршрутизаторе формат ответа по умолчанию JSON, поэтому каждый запрос без суффикса будет возвращать JSON.

Теперь в rspec я получаю ошибку (406) при попытке

get :index

мне нужно сделать

get :index, :format => :json

Теперь, так как я в основном поддерживаю JSON с моим API, очень избыточно указывать формат JSON для каждого запроса.

Могу ли я как-то установить его по умолчанию для всех моих запросов GET? (или все запросы)

Ваш Ответ

9   ответов
-3

Почему не используются методы RSpec, "get", "post", "put", "delete" работать в спецификации контроллера в гем (или за пределами Rails)?

Исходя из этого вопроса, вы можете попробовать переопределить process () в ActionController :: TestCase изhttps://github.com/rails/rails/blob/32395899d7c97f69b508b7d7f9b7711f28586679/actionpack/lib/action_controller/test_case.rb.

Вот мой обходной путь, хотя.

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
13

rspec 3:

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

Это устанавливаетHTTP_ACCEPT.

у меня это работает с Rails 5.0.1 + RSpec 3.5.2 + JBuilder 2.6.0.
работал здесь, чтобы о /
7

works for request specs, works with Rails 5, and does not involve private API of Rails (like process).

Вот конфигурация 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 можно разместить:

Directly in spec/spec_helper.rb. This is not suggested; the file will be loaded even when testing library methods in lib/.

Directly in spec/rails_helper.rb.

(my favorite) In spec/support/default_format.rb, and be loaded explicitly in spec/rails_helper.rb with

require 'support/default_format'

In spec/support, and be loaded by

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

which loads all the files in spec/support.

Это решение вдохновленоответ Knoopx, Его решение не работает для спецификации запроса, иalias_method_chain устарела в пользуModule#prepend.

47
before :each do
  request.env["HTTP_ACCEPT"] = 'application/json'
end
Где вы видите & quot; запрос & quot; переменная?
Это больше не работает в Rspec 3
Новый синтаксис Rspec 3 будет высоко ценится
Смотрите ответ RSpec 3 ниже:stackoverflow.com/a/25043739/1935918
@ Эрик, у тебя есть альтернативное предложение, так как оно не работает в Rspec 3?
2

которые работают с тестами запросов, самый простой способ, который я нашел, это переопределить#process метод вActionDispatch::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)
7

чтобы 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

я думалconfig.render_views было достаточно для получения ответов в виде JSON.
24

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
Может быть, все после действия должно быть дефолтным, чтобы не быть обязательным?
Это на самом деле не сработало для меня, но подобное решение сработало:snip2code.com/Snippet/13535/…
Это так мило! Спасибо, что поделился. И просто подсказка. Из-за того, что #merge используется в #process_with_default_params, вы все равно можете & quot; переопределить & quot; отформатируйте в своей спецификации что-то еще, кроме json - например, в html.
Здорово! Большое спасибо, это действительно полезно для меня :)
действительно отличный вариант
2

я достижения этой цели.

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

Это соответствует тому, что пример вдокументы похоже:

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
4

вы могли бы добавить первый ответ в 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 это должно работать со всеми версиями рельсов 4 вообще говоря.

Если вы измените его на config.before (: each, type:: controller), то он не будет соответствовать спецификациям модели.

Похожие вопросы