Как отправить исходные данные в функциональный тест 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'}