【问题标题】:In Rails Controller testing, is there a way to pass query (non-routing) parameters?在 Rails Controller 测试中,有没有办法传递查询(非路由)参数?
【发布时间】:2012-12-13 18:39:58
【问题描述】:

我在 Rails 和 RSpec 中编写控制器测试,从阅读ActionController::TestCase 的源代码看来,不可能将任意查询参数传递给控制器​​——只能传递路由参数。

为了解决这个限制,我目前使用的是with_routing

with_routing do |routes|
  # this nonsense is necessary because
  # Rails controller testing does not
  # pass on query params, only routing params

  routes.draw do 
    get '/users/confirmation/:confirmation_token' => 'user_confirmations#show'
    root :to => 'root#index'
  end

  get :show, 'confirmation_token' => CONFIRMATION_TOKEN
end

您可能已经猜到了,我正在为 Devise 测试一个自定义的 Confirmations 控制器。这意味着我正在插入现有的 API,并且无法更改 config/routes.rb 中的实际映射是如何完成的。

有没有更简洁的方法来做到这一点? get 是否支持传递查询参数的方式?


编辑:还有 其他事情正在发生。我在https://github.com/clacke/so_13866283 中创建了一个最小示例:

spec/controllers/receive_query_param_controller_spec.rb

describe ReceiveQueryParamController do
  describe '#please' do
    it 'receives query param, sets @my_param' do
      get :please, :my_param => 'test_value'
      assigns(:my_param).should eq 'test_value'
    end
  end  
end

app/controllers/receive_query_param_controller.rb

class ReceiveQueryParamController < ApplicationController
  def please
    @my_param = params[:my_param]
  end
end

config/routes.rb

So13866283::Application.routes.draw do
  get '/receive_query_param/please' => 'receive_query_param#please'
end

这个测试通过了,所以我想是 Devise 对路由做了一些时髦的事情。


编辑:

确定设计路线的定义位置,并更新了我的示例应用程序以匹配它。

So13866283::Application.routes.draw do
  resource :receive_query_param, :only => [:show],
    :controller => "receive_query_param"
end

...并且规格和控制器相应更新以使用#show。测试仍然通过,即params[:my_param]get :show, :my_param =&gt; 'blah' 填充。所以,为什么在我的真实应用中不会发生这种情况仍然是个谜。

【问题讨论】:

标签: ruby-on-rails ruby testing rspec


【解决方案1】:

控制器测试不路由。您正在对控制器进行单元测试——路由超出了它的范围。

一个典型的控制器规范示例测试一个动作:

describe MyController do
  it "is successful" do
    get :index
    response.status.should == 200
  end
end

您通过将参数传递给get 来设置测试上下文,例如:

  get :show, :id => 1

您可以在该哈希中传递查询参数。

如果您确实想测试路由,您可以编写路由规范,或请求(集成)规范。

【讨论】:

  • 我正在测试控制器,而不是路由。不幸的是,Rails 不允许我发送我想要的参数,因为 it 正在纠缠路由和控制器测试。这就是为什么我需要with_routing
  • 我想我明白这里发生了什么。您已经在 params 哈希中定义了一个需要 id 的资源,但您没有在规范中传递它。您应该能够简单地在该哈希中传递 id 和任何其他查询参数只要 id 存在。即:{ :id =&gt; "1", :hello =&gt; "world" }
  • 不,现有路由不需要:id 并且没有错误消息。 get 根本不传递我给它的任何参数,除非那些参数在路由路径中。
  • 确定 get :show 不需要:id 吗?路由是如何定义的?
  • rake routes CONTROLLER=user_confirmations 给我GET /users/confirmation(.:format) user_confirmations#show
【解决方案2】:

你确定没有其他事情发生吗?我有一个 Rails 3.0.x 项目并且正在传递参数.. 嗯.. 这是一篇文章.. 也许它与 get 不同,但这似乎很奇怪..

before  { post :contact_us, :contact_us => {:email => 'joe@example.com',
         :category => 'Category', :subject => 'Subject', :message => 'Message'} }

以上内容肯定在我的控制器中使用params 对象。

【讨论】:

  • 是的,我相信帖子的处理方式不同。代码只是偏向于获取查询参数,显然,“rails 方式”是将事物作为路径的一部分传递。我会检查 Devise 是如何测试自己的,也许那里有线索。
  • 哦,Devise 只对这个控制器进行集成测试,所以这个问题不会出现。
【解决方案3】:

我现在正在这样做:

@request.env['QUERY_STRING'] = "confirmation_token=" # otherwise it's ignored
get :show, :confirmation_token => CONFIRMATION_TOKEN

...但它看起来很老套。

如果有人可以向我展示一种简洁而正式的方式来做到这一点,我会很高兴。从我在#get 的源代码中看到的以及它调用的所有内容来看,似乎没有其他方法,但我希望我忽略了一些东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多