如何在rails 3function测试中发布JSON数据

我打算在我的项目中的请求和响应中使用JSON数据,并在测试中遇到一些问题。

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

 curl -H "Content-Type:application/json" -H "Accept:application/json" \ -d '{ "foo" : "bar" }' localhost:3000/api/new 

在控制器中,我可以使用params[:foo]访问JSON数据,这非常简单。 但是对于function测试,我只找到postxhrxml_http_request别名)。

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

这是我尝试过的。 我在action_controller/test_case.rb找到xhr的实现,并尝试添加jhr方法,只需更改’Conetent-Type’和’HTTP_ACCEPT’。 (在test/test_helpers.rb添加。)

 def json_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @request.env['Content-Type'] = 'Application/json' @request.env['HTTP_ACCEPT'] ||= [Mime::JSON, Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') __send__(request_method, action, parameters, session, flash).tap do @request.env.delete 'Content-Type' @request.env.delete 'HTTP_ACCEPT' end end alias jhr :json_http_request 

我以与xhr相同的方式使用它,但它不起作用。 我检查了@response对象并看到正文是" "

我还在Stack Overflow上找到了一个类似的问题 ,但它适用于rails 2,而发布原始数据的答案在rails 3中不起作用。

从Rails 5开始,执行此操作的方法是:

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

这也将正确设置Content-type标头(到application/json )。

我发现这正是我想要的 – 将JSON发布到控制器的动作中。

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

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

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

Json数据应该作为字符串,而不是哈希。 查看运行测试的堆栈跟踪,您可以获得对请求准备的更多控制:ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session.env_for

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

假设你有一个名为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 

希望这有助于其他人

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

 post :create, {param1: 'value1', param2: 'value2', format: 'json'} 

(花括号并不总是必要的,但有时如果它们丢失则不起作用,所以我总是添加它们。)

这是params和request.format对于那种post的样子:

params:{“param1”=>“value1”,“param2”=>“value2”,“format”=>“json”,“controller”=>“things”,“action”=>“create”}

request.format:application / json

我能想出的最佳答案是你没有

无论是否有意,导轨都不能为您实现这一点。

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

所以对于你的控制器,不要像通常那样传递你的params哈希传递JSON。 也许添加:格式作为参数,如果你需要检查并作出不同的反应。

如果要测试完整堆栈移动到IntegrationTest