Ruby on rails 如何在Rails3功能测试中发布JSON数据

Ruby on rails 如何在Rails3功能测试中发布JSON数据,ruby-on-rails,json,functional-testing,Ruby On Rails,Json,Functional Testing,我计划在项目的请求和响应中使用JSON数据,但在测试中遇到了一些问题 搜索了一段时间后,我发现以下代码使用curl发布JSON数据: curl -H "Content-Type:application/json" -H "Accept:application/json" \ -d '{ "foo" : "bar" }' localhost:3000/api/new 在控制器中,我可以使用params[:foo]访问JSON数据,这非常简单。但是对于功能测试,我只找到了post和xhr(

我计划在项目的请求和响应中使用JSON数据,但在测试中遇到了一些问题

搜索了一段时间后,我发现以下代码使用
curl
发布JSON数据:

curl -H "Content-Type:application/json" -H "Accept:application/json" \
    -d '{ "foo" : "bar" }' localhost:3000/api/new
在控制器中,我可以使用
params[:foo]
访问JSON数据,这非常简单。但是对于功能测试,我只找到了
post
xhr
(xml\u http\u请求的别名)

如何在rails中编写功能测试以达到与使用
curl
相同的效果?或者我应该以其他方式进行测试?

这是我试过的。我在
action\u controller/test\u case.rb
中找到了
xhr
的实现,并尝试添加
jhr
方法,只需更改“Conetent Type”和“HTTP\u ACCEPT”。(添加在
test/test\u helpers.rb
中)

我以与
xhr
相同的方式使用它,但它不起作用。我检查了
@response
对象,发现主体是


我还发现了堆栈溢出,但它适用于rails 2,发布原始数据的答案在rails 3中不起作用。

只需指定适当的内容类型:

post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'
Json数据应该作为字符串,而不是散列。 查看运行测试的堆栈跟踪,您可以获得对请求准备的更多控制: ActionDispatch::Integration::RequestHelpers.post=>=>


指定:格式不起作用,因为请求的格式为“application/x-www-form-urlencoded”,并且在处理请求正文时未正确解析json

正如@taro在上面的评论中所建议的,在功能和集成测试中适用于我的语法是:

post :create, {param1: 'value1', param2: 'value2', format: 'json'}
(花括号并不总是必需的,但有时如果缺少它们就不起作用,所以我总是添加它们。)

以下是此类帖子的params和request.format:

参数: {“param1”=>“value1”、“param2”=>“value2”、“format”=>“json”、“controller”=>“things”、“action”=>“create”}

request.format:
application/json

我发现这正是我想要的——将json发布到控制器的操作中

post :create, {:format => 'json', :user => { :email => "test@test.com", :password => "foobar"}}

假设您有一个名为api的控制器,一个名为new的方法,并且您正在测试api控制器:

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

这是我的窍门。

这里有一个片段,让我可以发布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

希望这对其他人有帮助

我能想出的最好答案是你不需要

不管这是否是故意的,rails不为您实现这一点可能是好事

在功能测试中,您真正想要的只是测试控制器,而不是rails的反序列化方法,甚至是路由和mime检测都设置正确,这些都属于IntegrationTest

因此,对于控制器,不要传递JSON,只需像平常一样传递参数散列即可。如果您需要检查并做出不同的响应,也可以添加:格式作为参数


如果您想测试从Rails 5开始将整个堆栈移动到

,方法是:

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

这也将正确设置
内容类型
标题(设置为
应用程序/json
)。

像往常一样编写功能测试,只需指定请求格式,如post:new、:foo=>'bar'、:format=>'json'我尝试过。但是响应的内容类型是“text/html”,主体是
。使用
xhr
进行post时,响应的内容类型为“application/json”,主体为json数据。直接设置字符串将得到以下错误
NoMethodError:undefined方法` symbol\u keys'表示“{\'foo\”:\“bar\”}:String
我使用rack test gem进行此类测试,也是因为它简化了许多请求的身份验证。在场景文件的顶部添加'require“rack/test'。这为我修复了它。非常奇怪的是,这对于Rails来说是必要的。。。这似乎是Rails的一个bug。我否决了这个问题,因为这个问题专门询问功能测试,并且尽我所能告诉您,只有在使用IntegrationTest时,才尊重内容类型。这是Rails 5的新正确答案。旧方法给出了弃用警告:ActionDispatch::IntegrationTest HTTP请求方法在未来的Rails版本中将只接受以下关键字参数:params、headers、env、xhr,as请求代码可以在actionpack-5.0.0.1/lib/action_dispatch/testing/integration.rb第326行method
process
中找到。但是没有将
作为
参数
post new_widget_url, as: :json, params: { foo: "bar" }