Ruby-on-rails 如何在 Rails 功能测试中发送原始帖子数据?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2103977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:10:21  来源:igfitidea点击:

How to send raw post data in a Rails functional test?

ruby-on-railsjsontesting

提问by brian

I'm looking to send raw post data (e.g. unparamaterized JSON) to one of my controllers for testing:

我希望将原始发布数据(例如未参数化的 JSON)发送到我的一个控制器进行测试:

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'
  end
end

but this gives me a NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>error.

但这给了我一个NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>错误。

What is the correct way to send raw post data in ActionController::TestCase?

发送原始帖子数据的正确方法是什么ActionController::TestCase

Here is some controller code:

这是一些控制器代码:

def index
  post_data = request.body.read
  req = JSON.parse(post_data)
end

回答by bbrowning

I ran across the same issue today and found a solution.

我今天遇到了同样的问题并找到了解决方案。

In your test_helper.rbdefine the following method inside of ActiveSupport::TestCase:

在您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

In your functional test, use it just like the postmethod but pass the raw post body as the third argument.

在您的功能测试中,像post方法一样使用它,但将原始帖子正文作为第三个参数传递。

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  test "sending json" do
    raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
  end
end

I tested this on Rails 2.3.4 when reading the raw post body using

我在使用 Rails 2.3.4 读取原始帖子正文时对此进行了测试

request.raw_post

instead of

代替

request.body.read

If you look at the source codeyou'll see that raw_postjust wraps request.body.readwith a check for this RAW_POST_DATAin the requestenv hash.

如果您查看源代码,您会看到它raw_post只是在env 哈希中request.body.read进行了检查。RAW_POST_DATArequest

回答by Andrea Reginato

I actually solved the same issues just adding one line before simulating the rspec post request. What you do is to populate the "RAW_POST_DATA". I tried to remove the attributes var on the post :create, but if I do so, it do not find the action.

我实际上解决了同样的问题,只是在模拟 rspec 发布请求之前添加了一行。您要做的是填充“RAW_POST_DATA”。我试图删除帖子上的属性 var:create,但如果我这样做,它找不到操作。

Here my solution.

这是我的解决方案。

def do_create(attributes)
  request.env['RAW_POST_DATA'] = attributes.to_json
  post :create, attributes
end 

In the controller the code you need to read the JSON is something similar to this

在控制器中,您需要读取 JSON 的代码与此类似

  @property = Property.new(JSON.parse(request.body.read))

回答by Grimmo

Looking at stack trace running a test you can acquire more control on request preparation: ActionDispatch::Integration::RequestHelpers.post => ActionDispatch::Integration::Session.process=> Rack::Test::Session.env_for

查看运行测试的堆栈跟踪,您可以获得对请求准备的更多控制:ActionDispatch::Integration::RequestHelpers.post => ActionDispatch::Integration::Session.process=> Rack::Test::Session.env_for

You can pass json string as :params AND specify a content type "application/json". In other case content type will be set to "application/x-www-form-urlencoded" and your json will be parsed properly.

您可以将 json 字符串作为 :params 传递并指定内容类型“application/json”。在其他情况下,内容类型将设置为“application/x-www-form-urlencoded”,并且您的 json 将被正确解析。

So all you need is to specify "CONTENT_TYPE":

所以你只需要指定“CONTENT_TYPE”:

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

回答by Artem Vasiliev

Version for Rails 5:

Rails 5 的版本:

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

See here- bodystring parameter is treated as raw request body.

请参阅此处-body字符串参数被视为原始请求正文。

回答by Rich

For those using Rails5+ integration tests, the (undocumented) way to do this is to pass a string in the params argument, so:

对于那些使用 Rails5+ 集成测试的人,(未记录的)方法是在 params 参数中传递一个字符串,所以:

post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }

回答by Daniel Salmeron Amselem

If you are using RSpec (>= 2.12.0) and writing Request specs, the module that is included is ActionDispatch::Integration::Runner. If you take a look at the source code you can notice that the postmethod calls processwhich accepts a rack_envparameter.

如果您使用 RSpec (>= 2.12.0) 并编写请求规范,则包含的模块是ActionDispatch::Integration::Runner. 如果您查看源代码,您会注意到post方法调用接受参数的processrack_env

All this means that you can simply do the following in your spec:

所有这一切意味着您可以简单地在规范中执行以下操作:

#spec/requests/articles_spec.rb

post '/articles', {}, {'RAW_POST_DATA' => 'something'}

And in the controller:

在控制器中:

#app/controllers/articles_controller.rb

def create
  puts request.body.read
end

回答by Tom Rossi

Using Rails 4, I was looking to do this to test the processing of raw xml that was being posted to the controller. I was able to do it by just providing the string to the post:

使用 Rails 4,我希望这样做是为了测试发布到控制器的原始 xml 的处理。我可以通过向帖子提供字符串来做到这一点:

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

I believe if the parameter provided is a string, it just gets passed along to the controller as the body.

我相信如果提供的参数是一个字符串,它只会作为主体传递给控制器​​。

回答by Juan Gomez

In rails, 5.1 the following work for me when doing a delete request that needed data in the body:

在 Rails 中,5.1 在执行需要正文中的数据的删除请求时,以下对我有用:

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

NOTE:This only works when doing an Integration test.

注意:这仅在进行集成测试时有效。

回答by Peb

I was searching very long for how to post raw JSON content in a integration test (Rails 5.1). I guess my solution could also help in this case. I looked up the documentation and source code for the postmethod: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-post

我一直在寻找如何在集成测试(Rails 5.1)中发布原始 JSON 内容。我想我的解决方案在这种情况下也有帮助。我查找了该方法的文档和源代码posthttps: //api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-post

This directed me to the processmethod for more details: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

这将我引导到该process方法以获取更多详细信息:https: //api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

Thanks to this, I finally found out what parameters are accepted by the processand thus postmethod. Here's what my final solution looked like:

多亏了这一点,我终于找到了processand 因此post方法接受了哪些参数。这是我的最终解决方案的样子:

post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json

回答by Andrew Goodnough

As of Rails 4.1.5, this was the only thing that worked for me:

从 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

for a url at /accounts/5/orders/10/items. This gets the url params conveyed as well as the JSON body. Of course, if orders is not embedded then you can leave off the params hash.

网址为 /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