我希望将原始发布数据(例如,未配置的JSON)发送到我的某个控制器进行测试:
class LegacyOrderUpdateControllerTest < ActionController::TestCase
test "sending json" do
post :index, '{"foo":"bar", "bool":true}'
end
end
但这会给我一个NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>
错误。
在ActionController::TestCase
中发送原始发布数据的正确方法是什么?
以下是一些控制器代码:
def index
post_data = request.body.read
req = JSON.parse(post_data)
end
答案 0 :(得分: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
在功能测试中,像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
如果您查看source code,您会看到raw_post
只是在request.body.read
env哈希中检查RAW_POST_DATA
request
。
答案 1 :(得分:17)
我实际上只添加了一行解决了同样的问题 在模拟rspec post请求之前。你做什么 是填充&#34; RAW_POST_DATA&#34;。我试图删除 帖子上的属性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))
答案 2 :(得分:9)
查看运行测试的堆栈跟踪,您可以获得对请求准备的更多控制: ActionDispatch :: Integration :: RequestHelpers.post =&gt; ActionDispatch::Integration::Session.process =&gt; 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'
答案 3 :(得分:5)
对于那些使用Rails5 +集成测试的人来说,(未记录的)方法是在params参数中传递一个字符串,所以:
post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
答案 4 :(得分:4)
如果您正在使用RSpec(&gt; = 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
答案 5 :(得分:4)
答案 6 :(得分:1)
使用Rails 4,我希望这样做来测试正在发布到控制器的原始xml的处理。我能够通过只为帖子提供字符串来实现:
raw_xml = File.read("my_raw.xml")
post :message, raw_xml, format: :xml
我相信如果提供的参数是一个字符串,它只是作为正文传递给控制器。
答案 7 :(得分:0)
post
方法需要名称 - 值对的散列,因此您需要执行以下操作:
post :index, :data => '{"foo":"bar", "bool":true}'
然后,在您的控制器中,获取要解析的数据:
post_data = params[:data]
答案 8 :(得分:0)
从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 params以及JSON正文。当然,如果没有嵌入订单,那么你可以省去params hash。
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
答案 9 :(得分:0)
在rails中,5.1在执行需要正文中的数据的删除请求时,以下工作:
delete your_app_url, as: :json, env: {
"RAW_POST_DATA" => {"a_key" => "a_value"}.to_json
}
注意:这仅在进行集成测试时有效。
答案 10 :(得分:0)
我一直在寻找如何在集成测试(Rails 5.1)中发布原始JSON内容的方法。我想我的解决方案在这种情况下也可能会有所帮助。
我查看了post
方法的文档和源代码: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
由于这一点,我终于找到了process
以及post
方法所接受的参数。
这是我最终的解决方案:
post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json
答案 11 :(得分:0)
在 Rails 4(至少在 4.2.11.3)中,没有简单的方法来测试使用 json 的控制器(功能测试)。为了在正在运行的服务器中解析 json,ActionDispatch::ParamsParser
middleware 负责。控制器测试虽然依赖于 Rack,但它无法解析 json to this day(不是它应该的)。
你可以这样做:
post :create, body_params.to_json
或:
post :update, body_parmas.to_json, url_params
但是 body_params
在控制器中无法通过 params
访问。你必须做JSON.parse(request.body.read)
。所以唯一想到的是:
post :update, url_params.merge(body_params)
也就是说,在测试中通过参数 (application/x-www-form-urlencoded
) 传递所有内容。在生产中,主体将被 ActionDispatch::ParamsParser
解析为相同的效果。除了你的数字变成字符串(可能更多):
# test/controllers/post_controller_test.rb
post :update, {id: 1, n: 2}
# app/controller/posts_controller.rb
def update
p params # tests:
# {"id"=>"1", "n" => "2", "controller"=>"posts", "action"=>"update"}
# production
# {"id"=>"1", "n" => 2, "controller"=>"posts", "action"=>"update"}
end
如果你愿意自己解析控制器中的 json,你可以这样做:
# test/controllers/post_controller_test.rb
post_json :update, {n: 2}.to_json, {id: 1}
# app/controller/posts_controller.rb
def update
p JSON.parse(request.body.read) # {"id"=>"1", "n" => 2, "controller"=>"posts", "action"=>"update"}
end
答案 12 :(得分:-5)
post :index, {:foo=> 'bar', :bool => 'true'}