Функциональный тест Rails: отправка параметров запроса URL в POST-запросе
я отправляю запрос POST в функциональном тесте Rails следующим образом:
post :create, collection: { name: 'New Collection' }
collection
отправляется как JSON-кодированные данные формы, как и ожидалось.
Я не могу понять, как добавить запрос к URL-адресу. документация говорит, что я могу получить доступ к объекту запроса и изменить его до его отправки. Поэтому я попробовал это:
@request.GET[:api_key] = 'my key'
post :create, collection: { name: 'New Collection' }
а, :api_key
никогда не появляется в request.GET
хэш на сервере. (Это происходит, когда я посылаю его, Хотя другой HTTP-клиент, однако.)
5 ответов
немного фона, чтобы сначала прояснить вещи: хотя запрос не может быть как получить, так и опубликовать одновременно, есть ничто не мешает вы используете как строку запроса, так и данные формы тела при использовании POST. Вы даже можете иметь сообщение со всеми параметрами в строке запроса и пустое тело, хотя это звучит довольно необычно.
Rails поддерживает этот сценарий, и действительно, Вы можете легко отправить форму с помощью запроса POST и по-прежнему запрос в action формы. Запрос будет доступен с помощью request.GET
хэш (это псевдоним query_string
), в то время как тело POST params с request.POST
хэш (псевдоним request_parameters
). The params
хэш фактически построен из в сочетании GET
и POST
хэши.
однако из моих исследований кажется, что Rails не поддерживает передачу строки запроса в запросах POST в тестах функциональных контроллеров. Хотя я не мог найти ничего об этом в документации или между известные проблемы на github исходный код вполне понятен. В следующем тексте я предполагаю, что вы используете Rails 4.
почему это не работает
проблема с функциональными тестами контроллера заключается в том, что они не используют реальные запросы / ответы, но имитируют HTTP-рукопожатие: запрос издевается, его параметры заполняются в соответствующих местах и заданном контроллере действие просто вызывается как обычный метод ruby. Все это делается в action_controller/test_case
классы.
как оказалось, эта симуляция не работает в вашем конкретном случае по двум причинам:
-
параметры при запуске теста всегда передала или до
request_parameters
, т. е.request.POST
хэш при использованииpost
запрос или кquery_string
(т. е.request.GET
) дляget
тестовых запросов. Невозможно установить оба этих хэша во время одного тестового запуска.это на самом деле имеет смысл как
get
,post
, etc. помощники в функциональных тестах принимают только один хэш параметров, поэтому внутренний тестовый код не может знать, как разделить их на два хэша. это правда, что можно установить запрос перед запуском теста с помощью
@request
переменной, но только до определенной степени, вы можете установить заголовки, например. Но!--38-->вы не можете установить внутренние атрибуты запрос, потому что они перерабатываются во время тестового запуска. Утилизация производится здесь и он сбрасывает все внутренние переменные объекта запроса и базового объекта запроса стойки. Поэтому, если вы попытаетесь настроить запрос, получите такие параметры, как@request.GET[:api_key] = 'my key'
, это не будет иметь никакого эффекта, поскольку внутренние переменные, представляющие этот хэш, получат протирается во время переработки.
решение
-
отказаться от функционального тестирования и выберите интеграционные тесты вместо. Интеграционные тесты разрешить устанавливать переменные среды стойки отдельно от основных параметров. Следующий интеграционный тест проходит
QUERY_STRING
переменная env шкафа кроме нормальных парамов тела столба и должна работать безупречно:class CollectionsTest < ActionDispatch::IntegrationTest test 'foo' do post collections_path, { collection: { name: 'New Collection' } }, { "QUERY_STRING" => "api_key=my_api_key" } # this proves that the parameters are recognized separately in the controller # (you can test this in you controller as well as here in the test): puts request.POST.inspect # => {"collection"=>{"name"=>"New Collection"}} puts request.GET.inspect # => {"api_key"=>"my_api_key"} end end
вы можете по-прежнему используйте большинство функций функциональных тестов в интеграционных тестах. Е. Г. вы можете проверить назначенные переменные в контроллер с
assigns
хэш.аргумент перехода поддерживается также тем, что рельсы 5 будет deprecate функциональные тесты контроллера в пользу интеграционного тестирования и так как Rails 5.1 эти функциональные тесты поддержки будут перемещены в отдельный драгоценный камень.
попробовать Rails 5: хотя функциональные тесты будут устаревшими, его исходный код, похоже, был сильно переписан в Rails master и, например, повторная обработка запроса больше не используется. Поэтому вы можете попробовать и попытаться установить внутренние переменные запроса во время настройки теста. Однако я не проверял его.
конечно, вы всегда можете попытаться исправить функциональный тест, чтобы он поддерживал отдельные параметры для
query_string
иrequest_parameters
хэши, определяемые в тестах.
я бы пошел по маршруту интеграционных тестов:).
Я предполагаю, что контроллер называется CollectionsController
и дороги на create
действие /collections
(если нет, вам просто нужно адаптировать пример ниже)
и я также предполагаю, что вы находитесь в спецификации запроса
это должно работать:
post '/collections?api_key=my_key', collection: { name: 'New Collection' }
второй аргумент в post
- это хэш всех параметров, которые вы получите в контроллере. Просто сделайте так:
post :create, collection: { name: 'New Collection' }, more_params: 'stuff', and_so_on: 'things'
эти параметры будут доступны в контроллере:
params[:and_so_on] == 'things'
вы хотите отправить запрос POST:
Я отправляю запрос POST в функциональном тесте Rails следующим образом:
но вы хотите получить данные из запроса GET:
а,
:api_key
никогда не появляется вrequest.GET
хэш на сервере.
запрос не может быть GET и POST одновременно, если вы отправляете запрос POST и передаете параметры в строке запроса, то у вас будут эти значения параметров доступный по запросу POST, GET просто ничего не будет.
затем:
@request.GET[:api_key] = 'my key'
post :create, collection: { name: 'New Collection' }
вы изменяете значения GET в запросе, но затем вы фактически отправляете запрос POST, что означает, что когда post
метод вызывается и запрос отправляется на сервер только то, что вы прислали на почту будет доступен. Просто отправьте ключ api в комплекте с запросом POST (может быть внутри хэша коллекции)
Это также проблема при тестировании действий POST с RSpec (v3.4).
обходным путем является издевательство над возвращаемым значением request.GET
или request.query_string
методы.
it "should recognise a query parameter in post action" do
allow(subject.request).to receive(:query_string).and_return("api_key=my%20key")
@params = {collection: { name: 'New Collection' }}
expect(subject.request.query_string).to eq "api_key=my%20key"
post :create, @params
end