【问题标题】:How to post JSON data in rails 3 functional test如何在 Rails 3 功能测试中发布 JSON 数据
【发布时间】:2011-08-16 00:19:42
【问题描述】:

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

找了一阵子,我发现下面的代码使用curl来发布JSON数据:

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

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

如何在rails中编写功能测试来达到和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 上找到 one similar question,但它适用于 rails 2,发布原始数据的答案在 rails 3 中不起作用。

【问题讨论】:

  • 像往常一样编写功能测试,只需指定请求格式,如 post :new, :foo => 'bar', :format => 'json'
  • 我试过了。但是响应的内容类型是“text/html”,正文是" "。使用xhr发帖时,响应的content-type为“application/json”,body为JSON数据。

标签: ruby-on-rails json functional-testing


【解决方案1】:

从 Rails 5 开始,这样做的方法是:

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

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

【讨论】:

  • 这是 Rails 5 的新正确答案。旧方法给出DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only the following keyword arguments in future Rails versions: params, headers, env, xhr, as
  • 请求代码可以在actionpack-5.0.0.1/lib/action_dispatch/testing/integration.rb第326行方法process中找到。但是doc 没有提到as 参数
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

    • 直接冒充字符串会报如下错误NoMethodError: undefined method `symbolize_keys' for "{ \"foo\" : \"bar\" }":String
    • 我使用 rack-test gem 来做这种测试也是因为它简化了许多请求的身份验证。在场景文件的顶部添加“require "rack/test"”。
    • 这为我解决了问题。虽然这对 Rails 来说是必需的,但很奇怪……似乎是一个 Rails 错误。
    • 我投了反对票,因为这个问题专门询问了功能测试,并且尽我所能告诉 CONTENT_TYPE 只有在您使用 IntegrationTest 时才会受到尊重
    【解决方案4】:

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

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

    为我做了诀窍。

    【讨论】:

      【解决方案5】:

      这是一个 sn-p,它让我发布 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
      

      希望这对其他人有所帮助

      【讨论】:

        【解决方案6】:

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

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

        (花括号并不总是必需的,但有时如果缺少它们就不起作用,所以我总是添加它们。)

        对于此类帖子,params 和 request.format 如下所示:

        参数: {"param1"=>"value1", "param2"=>"value2", "format"=>"json", "controller"=>"things", "action"=>"create"}

        request.format: 应用程序/json

        【讨论】:

          【解决方案7】:

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

          不管是不是故意的,rails 没有为你实现这个可能是件好事。

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

          因此,对于您的控制器,不要传递 JSON,只需像往常一样传递您的参数哈希。如果您需要检查并做出不同的响应,也许还可以添加 :format 作为参数。

          如果您想测试完整堆栈,请移至IntegrationTest

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-29
            • 2012-05-30
            • 2012-09-27
            相关资源
            最近更新 更多