Rails功能测试:在POST请求中发送URL查询参数

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

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

按照预期, collection将作为JSON编码的表单数据发送。

我无法弄清楚的是如何向URL添加查询。 该文档说我可以访问请求对象并在发送之前进行修改。 所以我试过这个:

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

但是, :api_key永远不会出现在服务器上的request.GET散列中。 (但是,当我通过另一个HTTP客户端发送它时,它会执行此操作。)


首先澄清一些事情:尽管请求不能同时使用GET和POST,但在使用POST时不会阻止使用查询字符串和正文表单数据。 你甚至可以在查询字符串中有一个包含所有参数的POST和一个空体,尽管这听起来很不寻常。

Rails支持这种情况,事实上,你可以使用POST请求轻松发送表单,并在表单的操作中仍然有查询。 查询将可以通过request.GET散列(它是query_string的别名)来访问,而POST正文使用request.POST散列( request_parameters的别名)。 params哈希实际上是由组合的GETPOST哈希构建的。

但是,从我的研究看来, Rails在功能控制器测试中不支持在POST请求中传递查询字符串 。 虽然在任何文档或github上的已知问题中,我都找不到任何关于此的内容,但源代码非常清晰。 在下面的文本中,我假设你使用Rails 4。

为什么它不起作用

功能控制器测试的问题在于它们不使用实际的请求/响应,而是模拟HTTP握手:请求被模拟,其参数填充到适当的位置,并且给定的控制器操作简单地称为普通的ruby方法。 所有这些都是在action_controller/test_case类中完成的。

事实证明,这种模拟不适用于您的具体情况,原因有两个:

  • 运行测试时传入的参数交给无论request_parameters ,即request.POST使用时哈希post请求query_string (即request.GET )用于get测试请求。 在单次测试运行期间,无法设置这两个哈希值。

    这实际上是有道理的,因为函数测试中的getpost等辅助函数只接受参数的单个散列值,所以内部测试代码无法知道如何将它们分离为两个散列值。

  • 确实,在使用@request变量运行测试之前,可以设置请求,但只有某种程度上,您可以设置标题。 但是你不能设置请求的内部属性 ,因为它们在测试运行期间被回收 。 回收在这里完成,它将重置请求对象和底层机架请求对象的所有内部变量。 所以如果你尝试设置request @request.GET[:api_key] = 'my key'这样的请求GET参数,它将不会产生任何影响,因为表示这个hash的内部变量在回收期间会被擦除。

  • 解决方案/解决方法

  • 放弃功能测试,并选择集成测试 。 集成测试允许将机架环境变量与主要参数分开设置。 以下集成测试通过QUERY_STRING rack env变量,除了正常的post body参数之外,应该完美地工作:

    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散列来测试控制器中已分配的实例变量。

    Rails 5支持集成测试不赞成使用功能控制器测试,而且这些功能测试支持的Rails 5.1将移出到单独的gem,这一事实也支持transition参数。

  • 尝试Rails 5:虽然功能测试将被弃用,但它的源代码似乎已经在rails主机中大量重写,并且例如请求的再循环不再被使用。 所以你可以尝试一下,在测试设置期间尝试设置请求的内部变量。 我还没有测试过它。

  • 当然,您可以尝试对功能测试进行猴式修补,以便它支持在测试中定义query_stringrequest_parameters哈希的单独参数。

  • 我会去集成测试路线:)。


    我假设控制器被命名为CollectionsController ,并且其create操作的路径是/collections (如果不是,您只需修改示例波纹管)

    而且我还假设你在一个请求规范中

    这应该工作:

    post '/collections?api_key=my_key', collection: { name: 'New Collection' }
    

    第二个参数post是你会收到在控制器则params的哈希值。 只要这样做:

    post :create, collection: { name: 'New Collection' }, more_params: 'stuff', and_so_on: 'things'
    

    这些参数将在控制器中提供:

    params[:and_so_on] == 'things'
    
    链接地址: http://www.djcxy.com/p/41091.html

    上一篇: Rails functional test: sending URL query parameters in POST request

    下一篇: HTTP post: url parameters and form data