json-如何在Rails功能测试中发送原始发布数据?

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

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

但这给了我ActionController::TestCase错误。

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

这是一些控制器代码:

def index
  post_data = request.body.read
  req = JSON.parse(post_data)
end
brian asked 2020-01-12T21:10:26Z
12个解决方案
55 votes

我今天遇到了同一问题,找到了解决方案。

raw_post中的request.body.read内部定义以下方法:

def raw_post(action, params, body)
  @request.env['RAW_POST_DATA'] = body
  response = post(action, params)
  @request.env.delete('RAW_POST_DATA')
  response
end

在功能测试中,就像使用raw_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 env哈希中的RAW_POST_DATA的支票包装了request.body.read

bbrowning answered 2020-01-12T21:10:56Z
18 votes

我实际上只添加了一行就解决了相同的问题在模拟rspec发布请求之前。 你做什么是要填充“ 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))
Andrea Reginato answered 2020-01-12T21:11:26Z
9 votes

查看运行测试的堆栈跟踪,您可以根据请求准备获得更多控制权:ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process =>机架::测试:: 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'
Grimmo answered 2020-01-12T21:11:55Z
7 votes

对于那些使用Rails5 +集成测试的人,(未记录)执行此操作的方法是在params参数中传递字符串,因此:

post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
Rich answered 2020-01-12T21:12:15Z
4 votes

如果使用RSpec(> = 2.12.0)并编写请求规范,则包含的模块是ActionDispatch::Integration::Runner。如果查看源代码,您会注意到post方法调用process接受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
Daniel Salmeron Amselem answered 2020-01-12T21:12:44Z
4 votes

Rails 5的版本:

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

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

Artem Vasiliev answered 2020-01-12T21:13:08Z
1 votes

我正在使用Rails 4来测试发布到控制器上的原始xml的处理。 我只需要提供字符串就可以做到:

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

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

Tom Rossi answered 2020-01-12T21:13:33Z
0 votes

post方法需要使用名称/值对的哈希,因此您需要执行以下操作:

post :index, :data => '{"foo":"bar", "bool":true}'

然后,在您的控制器中,获取要解析的数据,如下所示:

post_data = params[:data]
Alex Reisner answered 2020-01-12T21:13:57Z
0 votes

从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

在/ 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
Andrew Goodnough answered 2020-01-12T21:14:22Z
0 votes

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

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

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

Juan Gomez answered 2020-01-12T21:14:46Z
0 votes

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

这将我引向process方法,以了解更多详细信息:[https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process]

因此,我终于找到了processpost方法所接受的参数。这是我最终的解决方案:

post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json
Peb answered 2020-01-12T21:15:16Z
-5 votes
post :index, {:foo=> 'bar', :bool => 'true'}
Sohan answered 2020-01-12T21:15:32Z
translate from https://stackoverflow.com:/questions/2103977/how-to-send-raw-post-data-in-a-rails-functional-test