Функциональный тест 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 классы.

как оказалось, эта симуляция не работает в вашем конкретном случае по двум причинам:

  1. параметры при запуске теста всегда передала или до request_parameters, т. е. request.POST хэш при использовании post запрос или к query_string (т. е. request.GET) для get тестовых запросов. Невозможно установить оба этих хэша во время одного тестового запуска.

    это на самом деле имеет смысл как get, post, etc. помощники в функциональных тестах принимают только один хэш параметров, поэтому внутренний тестовый код не может знать, как разделить их на два хэша.

  2. это правда, что можно установить запрос перед запуском теста с помощью @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