繁体   English   中英

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

[英]Rails functional test: sending URL query parameters in POST request

我在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的别名)进行request_parameters params散列实际上是由组合的GETPOST哈希构造的。

但是,根据我的研究,似乎Rails不支持在功能控制器测试中的POST请求中传递查询字符串 虽然我在github的任何文档或已知问题中找不到任何相关内容,但源代码非常清楚。 在下文中,我假设您使用Rails 4。

为什么它不起作用

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

事实证明,由于两个原因,此模拟在您的特定情况下不起作用:

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

    这实际上是有道理的,因为功能测试中的getpost等帮助程序只接受params的单个哈希,因此内部测试代码无法知道如何将它们分成两个哈希。

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

解决方案/解决方法

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

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

    转换参数也受到以下事实的支持: Rails 5将弃用功能控制器测试以支持集成测试,并且由于Rails 5.1这些功能测试支持将被移出到单独的gem。

  • 试试Rails 5:虽然功能测试将被弃用,但它的源代码似乎已经在rails master中大量重写 ,例如,不再使用请求的回收。 因此,您可以尝试尝试在测试设置期间设置请求的内部变量。 我没有测试过它。

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

我去集成测试路线:)。

我假设控制器名为CollectionsController ,它create动作的路径是/collections (如果没有,你只需要调整下面的例子)

而且我还假设您处于请求规范中

这应该工作:

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

post的第二个参数是你将在控制器中收到的所有参数的哈希值。 这样做:

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

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

params[:and_so_on] == 'things'

您想发送POST请求:

我在Rails功能测试中发送POST请求,如下所示:

但是您想要从GET请求中检索数据:

但是, :api_key永远不会出现在服务器上的request.GET哈希中。

请求不能同时是GET和POST,如果您要发送POST请求并在查询字符串中传递参数,那么您将在POST请求中获得这些参数值,GET就没有任何内容。

然后:

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

您正在修改请求中的GET值,但实际上您发送了一个POST请求,这意味着当调用post方法并将请求发送到服务器时,只有您在POST上发送的内容才可用。 只需发送与POST请求捆绑在一起的api密钥(可能在集合哈希内部)

使用RSpec(v3.4)测试POST操作时,这也是一个问题。

解决方法是模拟request.GETrequest.query_string方法的返回值。

it "should recognise a query parameter in post action" do
  allow(subject.request).to receive(:query_string).and_return("api_key=my%20key")  
  @params = {collection: { name: 'New Collection' }}


  expect(subject.request.query_string).to eq "api_key=my%20key"

  post :create, @params
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM