本文介绍了Rails功能测试:在POST请求中发送URL查询参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在这样的Rails功能测试中发送POST请求:

I'm sending a POST request in a Rails functional test like this:

post :create, collection: { name: 'New Collection' }

collection被发送为JSON编码的表单数据,符合预期.

collection gets sent as JSON-encoded form data, as expected.

我不知道如何在URL中添加查询. 文档说,我可以访问请求对象并在发送请求之前对其进行修改.所以我尝试了这个:

What I can't figure out is how to add a query to the URL. The documentation says that I can access the request object and modify it before it gets sent. So I tried this:

@request.GET[:api_key] = 'my key'
post :create, collection: { name: 'New Collection' }

但是,:api_key永远不会出现在服务器上的request.GET哈希中. (不过,当我通过另一个HTTP客户端发送它时也是如此.)

But, :api_key never appears in the request.GET hash on the server. (It does when I send it though another HTTP client, though.)

推荐答案

首先要弄清楚背景:尽管请求不能同时是GET和POST,但是有同时使用查询字符串和正文形式数据.您甚至可以在查询字符串中包含所有参数的POST,并留空身体,尽管听起来很不寻常.

A little background first to clarify things: although a request cannot be both GET and POST at the same time, there is nothing stopping you from using both the query string and body form data when using POST. You can even have a POST with all parameters in the query string and an empty body, though this sounds quite unusual.

Rails支持这种情况,实际上,您可以轻松地使用POST请求发送表单,并且仍然可以对表单进行查询.该查询将通过 request.GET哈希(这是query_string的别名),而POST正文使用 request.POST哈希(request_parameters的别名). params哈希实际上是根据组合的和POST哈希.

Rails supports this scenario and indeed you can easily send a form using a POST request and still have query in the form's action. The query will be accessible with request.GET hash (which is an alias of query_string), while the POST body params with the request.POST hash (an alias of request_parameters). The params hash is actually constructed from the combined GET and POST hashes.

但是,从我的研究看来, Rails不支持在功能控制器测试中的POST请求中传递查询字符串.尽管我在任何文档中或 github上的已知问题,源代码非常清晰.在下面的文本中,我假设您使用Rails 4.

However, from my research it seems that Rails does not support passing query string in POST requests in functional controller tests. Although I could not find anything regarding this in any documentation or among known issues on github, the source code is quite clear. In the following text, I'm assuming that you use Rails 4.

功能性控制器测试的问题在于它们不使用实际的请求/响应,而是模拟HTTP握手:模拟请求,将其参数填充在适当的位置,并且将给定的控制器操作简单地称为正常操作红宝石方法.所有这些都是在.

The problem with functional controller tests is that they don't use real requests / responses but they simulate the HTTP handshake: the request is mocked up, its parameters filled in appropriate places and the given controller action is simply called as a normal ruby method. All of this is done in the action_controller/test_case classes.

事实证明,由于以下两个原因,该模拟不适用于您的特定情况:

As it turns out, this simulation is not working in your particular case, due to two reasons:

  1. 运行测试时传递的参数总是 移交 两个request_parameters,即使用post请求时request.POST哈希get测试请求,请选择query_string(即request.GET).在单个测试运行中无法同时设置这两个哈希值.

  1. The parameters passed in when running the test are always handed over either to the request_parameters, i.e. the request.POST hash when using a post request or to the query_string (i.e. request.GET) for get test requests. There is no way for both of these hashes to be set during a single test run.

这实际上与getpost等类似.在功能测试中,辅助函数仅接受一个参数散列,因此内部测试代码无法知道如何将它们分为两个散列.

This actually makes some sense as the get, post, etc. helpers in functional tests accept only a single hash of params so the internal test code cannot know how to separate them into the two hashes.

的确可以在使用@request变量运行测试之前设置请求,但是例如,可以在一定程度上设置标头.但是您不能设置请求的内部属性,因为它们在测试运行期间被回收.回收是在此处完成的a>,它将重置请求对象和基础机架请求对象的所有内部变量.因此,如果尝试设置像@request.GET[:api_key] = 'my key'这样的请求GET参数,则该参数将无效,因为代表该哈希的内部变量将在回收期间被擦除.

It is true that one can set up the request before running the test using the @request variable, but only to a certain extent, you can set headers, for example. But you cannot set internal attributes of the request, because they are recycled during the test run. The recycling is done here and it resets all internal variables of the request object and the underlying rack request object. So if you try to set up the request GET parameters like this @request.GET[:api_key] = 'my key', it won't have any effect as the internal variables representing this hash will get wiped during recycling.

解决方案/解决方法

  • 放弃功能测试,并选择集成测试.集成测试可以设置机架环境变量与主要参数分开.以下集成测试除了通过普通的柱体参数之外还通过了QUERY_STRING rack env变量,并且可以正常工作:

    Solutions / workarounds

    • Give up functional testing and choose integration tests instead. Integration tests allow to set the rack environment variables separately from the main parameters. The following integration test passes the QUERY_STRING rack env variable besides the normal post body params and should work flawlessly:

      class CollectionsTest < ActionDispatch::IntegrationTest
        test 'foo' do
          post collections_path, { collection: { name: 'New Collection' } },
                                 { "QUERY_STRING" => "api_key=my_api_key" }
      
          # this proves that the parameters are recognized separately in the controller
          # (you can test this in you controller as well as here in the test):
          puts request.POST.inspect
          # => {"collection"=>{"name"=>"New Collection"}}
          puts request.GET.inspect
          # => {"api_key"=>"my_api_key"}
        end
      end
      

      您仍然可以在集成测试中使用功能测试中的大多数功能.例如.您可以使用assigns哈希在控制器中测试分配的实例变量.

      You can still use most of the features from functional tests in your integration tests. E.g. you can test for assigned instance variables in the controller with the assigns hash.

      Rails 5将不赞成支持集成测试的功能控制器测试,并且从Rails 5.1开始,这些功能测试支持将移至单独的gem.

      The transition argument is supported also by the fact that Rails 5 will deprecate functional controller tests in favor of integration testing and since Rails 5.1 these functional tests support will be moved out to a separate gem.

      尝试使用Rails 5:尽管不建议使用功能测试,但其源代码似乎已经在Rails主目录中大量重写,例如请求的回收已不再使用.因此,您可以尝试在测试设置过程中尝试设置请求的内部变量.我还没有测试过.

      Try Rails 5: although functional tests will be deprecated, its source code seems to have been heavily rewritten in the rails master and e.g. recycling of the request is not used any more. So you might give it a try and try to set the internal variables of the request during test setup. I have not tested it though.

      当然,您总是可以尝试对功能测试进行猴子修补,以使其支持要在测试中定义的query_stringrequest_parameters哈希的单独参数.

      Of course, you can always try to monkey-patch the functional test so that it supports separate params for the query_string and request_parameters hashes to be defined in tests.

      我会去进行集成测试:).

      I'd go the integration tests route :).

      这篇关于Rails功能测试:在POST请求中发送URL查询参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 05:49
查看更多