我在Rails功能测试中发送POST请求,如下所示:
post :create, collection: { name: 'New Collection' }
正如预期的那样, collection
将作为JSON编码的表单数据发送。
我无法弄清楚如何向网址添加查询。 The documentation表示我可以访问请求对象并在发送之前对其进行修改。所以我尝试了这个:
@request.GET[:api_key] = 'my key'
post :create, collection: { name: 'New Collection' }
但是,:api_key
永远不会出现在服务器上的request.GET
哈希中。 (但是,当我通过另一个HTTP客户端发送它时,它会这样做。)
答案 0 :(得分:18)
首先要澄清一些事情:虽然请求不能同时是GET和POST,但是在使用POST时,nothing stopping您可以使用查询字符串和正文表单数据。您甚至可以使用查询字符串and an empty body中的所有参数进行POST,但这听起来很不寻常。
Rails支持这种情况,实际上您可以使用POST请求轻松发送表单,并且仍然可以在表单的操作中进行查询。可以使用request.GET
hash(query_string
的别名)访问该查询,而POST正文使用request.POST
hash(别名为request_parameters
)进行访问。 params
哈希实际上是从combined GET
and POST
hashes构建的。
然而,根据我的研究,似乎 Rails不支持在功能控制器测试中的POST请求中传递查询字符串。虽然我在任何文档或known issues on github中找不到任何相关内容,但源代码非常清楚。在下文中,我假设您使用Rails 4。
功能控制器测试的问题在于他们没有使用真实的请求/响应,但他们模拟HTTP握手:请求被模拟,其参数填充在适当的位置,并且给定的控制器操作被简单地称为一种普通的红宝石方法。所有这些都是在action_controller/test_case
classes。
事实证明,由于两个原因,此模拟在您的特定情况下不起作用:
运行测试时传入的参数始终 handed over 至request_parameters
,即{{1}对request.POST
请求使用post
请求或到query_string
(即request.GET
)时的哈希值。在单次测试运行期间,无法设置这两个哈希值。
这实际上是有道理的,因为功能测试中的get
,get
等助手只接受params的单个哈希,因此内部测试代码无法知道如何将它们分成两个哈希
确实可以在使用post
变量运行测试之前设置请求,但仅在某种程度上,您可以设置标题,例如。但是您无法设置请求的内部属性,因为在测试运行期间它们会被回收。回收完成here并重置请求对象和底层机架请求对象的所有内部变量。因此,如果您尝试设置请求GET参数(例如此@request
),则它不会产生任何影响,因为在回收期间将代表此哈希的内部变量被擦除。
放弃功能测试,选择集成测试。集成测试allow to set the rack environment variables与主要参数分开。以下集成测试除了正常的post body params之外还传递@request.GET[:api_key] = 'my key'
rack env变量,并且应该完美无缺地运行:
QUERY_STRING
您仍然可以在集成测试中使用功能测试中的大多数功能。例如。您可以使用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
哈希测试控制器中已分配的实例变量。
Rails 5将deprecate功能控制器测试支持集成测试这一事实也支持转换参数,并且由于Rails 5.1这些功能测试支持将被移出到单独的宝石。
试用Rails 5:虽然不推荐使用功能测试,但它的源代码似乎在rails master中是heavily rewritten,例如不再使用请求的回收。因此,您可以尝试尝试在测试设置期间设置请求的内部变量。我没有测试过它。
当然,您总是可以尝试对功能测试进行修补,以便它支持在测试中定义assigns
和query_string
哈希的单独参数。
我去集成测试路线:)。
答案 1 :(得分:2)
我假设控制器名为CollectionsController
,其create
操作的路由为/collections
(如果不是,您只需调整下面的示例)
我还假设您处于请求规范
这应该有效:
post '/collections?api_key=my_key', collection: { name: 'New Collection' }
答案 2 :(得分:1)
post
的第二个参数是您在控制器中收到的所有参数的哈希值。就这样做:
post :create, collection: { name: 'New Collection' }, more_params: 'stuff', and_so_on: 'things'
这些参数将在控制器中提供:
params[:and_so_on] == 'things'
答案 3 :(得分:1)
您想发送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密钥(可能在集合哈希内部)
答案 4 :(得分:0)
使用RSpec(v3.4)测试POST操作时,这也是一个问题。
解决方法是模拟request.GET
或request.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