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

bri*_*ian 53 testing json ruby-on-rails

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

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'
  end
end
Run Code Online (Sandbox Code Playgroud)

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

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

这是一些控制器代码:

def index
  post_data = request.body.read
  req = JSON.parse(post_data)
end
Run Code Online (Sandbox Code Playgroud)

小智 55

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

在您的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
Run Code Online (Sandbox Code Playgroud)

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

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  test "sending json" do
    raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
  end
end
Run Code Online (Sandbox Code Playgroud)

我在阅读原始帖子体时使用Rails 2.3.4测试了这个

request.raw_post
Run Code Online (Sandbox Code Playgroud)

代替

request.body.read
Run Code Online (Sandbox Code Playgroud)

如果你看一下源代码,你会看到raw_post只是在env哈希中request.body.read检查了这个.RAW_POST_DATArequest

  • 在Rails 4中,不再需要这样做.如果传递给`post`的第二个arg是一个String,它将被视为`RAW_POST_DATA`.例如`post:create,'{"foo":"bar","bool":true}'` (14认同)

And*_*ato 18

在模拟rspec post请求之前,我实际上解决了相同的问题,只需添加一行.你要做的是填充"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))


小智 11

我一直在寻找如何在集成测试(Rails 5.1)中发布原始 JSON 内容。我想我的解决方案在这种情况下也能有所帮助。我查找了该方法的文档和源代码posthttps://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

process多亏了这个,我终于找到了and方法接受哪些参数post。这是我的最终解决方案:

post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json
Run Code Online (Sandbox Code Playgroud)


Gri*_*mmo 9

查看运行测试的堆栈跟踪,您可以获得对请求准备的更多控制:ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: 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'
Run Code Online (Sandbox Code Playgroud)

  • 这对我不起作用.我得到一个错误,如"<String:0x00000102b4b0d8>"的"未定义方法`symbolize_keys'" (5认同)

Ric*_*ich 7

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

post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
Run Code Online (Sandbox Code Playgroud)

  • 这在 Rails 5.1 中不再对我有用。如果你查看 request.body.read - 它是空的。 (2认同)

Art*_*iev 5

Rails 5的版本:

post :create, body: '{"foo": "bar", "bool": true}'
Run Code Online (Sandbox Code Playgroud)

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

  • 在 Rails 5.2+ 中工作得很好。数据可在控制器中作为 request.raw_post 访问。 (2认同)
  • 在 Rails 6.0 中工作得非常好。IMO 这应该是公认的答案。 (2认同)