Как отправить исходные данные в функциональный тест Rails?

Я хочу отправить исходные данные (например, unparamaterized json) на один из моих контроллеров для тестирования:

class LegacyOrderUpdateControllerTest < ActionController::TestCase
 test "sending json" do
   post :index, '{"foo":"bar", "bool":true}'
 end
end

но это дает мне NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>

Каков правильный способ отправки исходных данных в ActionController:: TestCase?

Вот какой код контроллера

def index
    post_data = request.body.read
    req = JSON.parse(post_data)

Ответы

Ответ 1

Сегодня я столкнулся с той же проблемой и нашел решение.

В вашем test_helper.rb определите следующий метод внутри ActiveSupport:: TestCase:

  def raw_post(action, params, body)
    @request.env['RAW_POST_DATA'] = body
    response = post(action, params)
    @request.env.delete('RAW_POST_DATA')
    response
  end

В своем функциональном тесте используйте его так же, как метод post, но передайте исходное тело сообщения в качестве третьего аргумента.

class LegacyOrderUpdateControllerTest < ActionController::TestCase
 test "sending json" do
   raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
 end
end

Я тестировал это на Rails 2.3.4 при чтении исходного тела сообщения с помощью

request.raw_post

вместо

request.body.read

Если вы посмотрите на исходный код, вы увидите, что raw_post просто обертывает request.body.read с проверкой для этого RAW_POST_DATA в запрос env hash.

Ответ 2

Я фактически решил те же проблемы, просто добавив одну строку перед имитацией запроса rspec post. Что ты делаешь заключается в заполнении "RAW_POST_DATA". Я попытался удалить атрибуты var в сообщении: create, но если я это сделаю, он не находит действие.

Здесь мое решение.

def do_create(attributes)
  request.env['RAW_POST_DATA'] = attributes.to_json
  post :create, attributes
end 

В контроллере код, необходимый для чтения JSON, что-то похожее на это

  @property = Property.new(JSON.parse(request.body.read))

Ответ 3

Если посмотреть на трассировку стека, в которой выполняется тест, вы можете получить больше контроля при подготовке запроса: ActionDispatch:: Integration:: RequestHelpers.post = > ActionDispatch:: Integration:: Session.process = > Rack:: Test:: Session.env_for

Вы можете передать строку json как: params И указать тип контента "application/json". В другом случае тип содержимого будет установлен в "application/x-www-form-urlencoded", и ваш json будет правильно разбираться.

Итак, все, что вам нужно, это указать "CONTENT_TYPE":

post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'

Ответ 4

Если вы используете RSpec ( >= 2.12.0) и записываете спецификации запроса, модуль, который включен, ActionDispatch::Integration::Runner. Если вы посмотрите на исходный код, вы заметите, что метод post вызывает процесс, который принимает параметр rack_env.

Все это означает, что вы можете просто сделать следующее в своей спецификации:

#spec/requests/articles_spec.rb

post '/articles', {}, {'RAW_POST_DATA' => 'something'}

И в контроллере:

#app/controllers/articles_controller.rb

def create
  puts request.body.read
end

Ответ 5

Версия для Rails 5:

post :create, body: '{"foo": "bar", "bool": true}'

См. здесь - body Строковый параметр обрабатывается как тело необработанного запроса.

Ответ 6

Для тех, кто использует тесты интеграции Rails5 +, способ (недокументированный) для этого - передать строку в аргументе params, поэтому:

post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }

Ответ 7

Используя Rails 4, я пытался сделать это, чтобы протестировать обработку raw xml, который был отправлен в контроллер. Я смог сделать это, просто предоставив строку в сообщение:

raw_xml = File.read("my_raw.xml")
post :message, raw_xml, format: :xml

Я считаю, что если предоставленный параметр является строкой, он просто передается вместе с контроллером как тело.

Ответ 8

Метод post ожидает хэш пар имя-значение, поэтому вам нужно сделать что-то вроде этого:

post :index, :data => '{"foo":"bar", "bool":true}'

Затем, в вашем контроллере, получите данные для анализа следующим образом:

post_data = params[:data]

Ответ 9

Как и Rails 4.1.5, это единственное, что сработало для меня:

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  def setup
    @request.headers["Content-Type"] = 'application/json'
  end

  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'.to_json, { account_id: 5, order_id: 10 }
  end
end

для URL-адреса в /accounts/ 5/orders/10/items. Это получает переданные параметры URL, а также тело JSON. Конечно, если заказы не встроены, вы можете оставить хеш params.

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  def setup
    @request.headers["Content-Type"] = 'application/json'
  end

  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'.to_json
  end
end

Ответ 10

В rails 5.1 для меня выполняется следующая работа при выполнении запроса на удаление, в котором необходимы данные в теле:

delete your_app_url, as: :json, env: {
   "RAW_POST_DATA" =>  {"a_key" => "a_value"}.to_json
}

ПРИМЕЧАНИЕ: Это работает только при выполнении теста интеграции.

Ответ 11

post :index, {:foo=> 'bar', :bool => 'true'}