Как опубликовать данные JSON в rails 3 функциональных теста

Я планирую использовать данные JSON как в запросе, так и в ответе в моем проекте и испытываю некоторые проблемы при тестировании.

После некоторого поиска я найду следующий код, который использует curl для публикации данных JSON:

curl -H "Content-Type:application/json" -H "Accept:application/json" \
    -d '{ "foo" : "bar" }' localhost:3000/api/new

В контроллере я могу получить доступ к данным JSON, просто используя params[:foo], что очень просто. Но для функционального тестирования я нахожу только post и xhr (псевдоним для xml_http_request).

Как написать функциональный тест в рельсах для достижения того же эффекта, что и при использовании curl? Или мне нужно проводить тесты другими способами?

Вот что я пробовал. Я нахожу реализацию для xhr в action_controller/test_case.rb и пытаюсь добавить метод jhr, просто изменяя "Conetent-Type" и "HTTP_ACCEPT". (Добавлено в test/test_helpers.rb.)

def json_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
  @request.env['Content-Type'] = 'Application/json'
  @request.env['HTTP_ACCEPT'] ||= [Mime::JSON, Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
  __send__(request_method, action, parameters, session, flash).tap do
    @request.env.delete 'Content-Type'
    @request.env.delete 'HTTP_ACCEPT'
  end
end
alias jhr :json_http_request

Я использовал это так же, как xhr, но он не работает. Я проверил объект @response и увидел, что тело " ".

Я также нахожу один похожий вопрос в Stack Overflow, но он для rails 2, и ответ на отправку необработанных данных не работает в rails 3.

Ответ 1

Я обнаружил, что это делает именно то, что я хочу - отправьте JSON на действие контроллера.

post :create, {:format => 'json', :user => { :email => "[email protected]", :password => "foobar"}}

Ответ 2

Просто укажите соответствующий тип контента:

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

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

Задание: формат не работает, потому что запрос идет как "application/x-www-form-urlencoded", а json не обрабатывается правильно обработкой тела запроса.

Ответ 3

Как и в случае с Rails 5, способ сделать это:

post new_widget_url, as: :json, params: { foo: "bar" }

Непонятно, что он правильно устанавливает заголовок Content-type - это большое количество фальшивщиков, участвующих в этих тестах интеграции, - но запрашивающие данные, похоже, правильно добираются до контроллера.

Ответ 4

Предполагая, что у вас есть контроллер с именем api, метод с именем new, и вы находитесь в тесте для контроллера api:

@request.env["RAW_POST_DATA"] = '{ "foo" : "bar" }'
post :new

сделал трюк для меня.

Ответ 5

Вот фрагмент, который позволяет мне публиковать json-данные для тестирования собственного приложения. рельсы 3

port = Rails.env.production? ? 80 : 3000
uri = URI.parse( Rails.application.routes.url_helpers.books_url(:host => request.host, :port => port, :format => :json) )
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.content_type = 'application/json'
request.body = @json_data
response = http.request( request )
@result = response.body

Надеюсь, что это поможет другим людям.

Ответ 6

Как указывает @taro в комментарии выше, синтаксис, который работает для меня в функциональных и интеграционных тестах:

post :create, {param1: 'value1', param2: 'value2', format: 'json'}

(фигурные скобки не всегда необходимы, но иногда они не работают, если они отсутствуют, поэтому я всегда добавляю их.)

Здесь какие параметры и request.format выглядят для сообщения такого типа:

Титулы: { "param1" = > "value1", "param2" = > "value2", "format" = > "json", "controller" = > "things", "action" = > "create" }

request.format: Применение/JSON

Ответ 7

Лучший ответ, который я могу придумать, заключается в том, что вы не

Было ли это намеренно, возможно, хорошо, что рельсы не реализуют это для вас.

В функциональных тестах вы действительно хотите просто протестировать свой дескриптор контроллера, а не рельсы, даже если настройка маршрутизации и мимирования настроена правильно, все они попадают под интеграционный тест.

Итак, для ваших контроллеров, не пропустите JSON, просто передайте свой парашют params, как обычно. Возможно, добавление: формат как аргумент, если вам нужно проверить это и ответить по-другому.

Если вы хотите протестировать полный переход стека в IntegrationTest