Как отправить необработанные данные в функциональном тесте Rails? - PullRequest
52 голосов
/ 20 января 2010

Я хочу отправить необработанные данные поста (например, непараметизированный 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)
end

Ответы [ 12 ]

55 голосов
/ 21 января 2010

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

В вашем 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 в хэше request env.

17 голосов
/ 12 января 2011

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

Вот мое решение.

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))
9 голосов
/ 28 октября 2011

Глядя на трассировку стека при выполнении теста, вы можете получить больше контроля при подготовке запроса: 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'
6 голосов
/ 26 июня 2017

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

post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
4 голосов
/ 25 апреля 2017

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

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

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

4 голосов
/ 28 января 2013

Если вы используете RSpec (> = 2.12.0) и пишете спецификации запроса, включается модуль ActionDispatch::Integration::Runner. Если вы посмотрите на исходный код, то заметите, что метод post вызывает process , который принимает параметр 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
1 голос
/ 14 мая 2015

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

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

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

0 голосов
/ 16 августа 2018

Я очень долго искал, как разместить необработанный контент JSON в интеграционном тесте (Rails 5.1). Я думаю, мое решение также может помочь в этом случае. Я посмотрел документацию и исходный код для метода post: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-post

Это привело меня к методу process для более подробной информации: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

Благодаря этому я наконец выяснил, какие параметры принимаются методом process и, следовательно, post. Вот как выглядело мое окончательное решение:

post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json
0 голосов
/ 31 октября 2017

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

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

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

0 голосов
/ 19 мая 2015

Начиная с 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-адреса в / account / 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...