如何使用rspec测试控制器中的所有路由

时间:2012-10-15 20:05:07

标签: ruby-on-rails rspec capybara

我正在尝试限制我的应用中的一些控制器,以便在执行任何操作之前需要登录。我知道如何实现它,但不知道如何在rspec中为它编写好的测试。

例如,如果我想限制我的用户控制器的每个操作都要求登录,我可以进行如下测试:

描述“授权”做

describe "for non-signed-in users" do
  let(:user) { FactoryGirl.create(:user) }

  describe "in the Users controller" do

    describe "visiting the index page" do
      before { visit users_path }
      it { should have_selector('title', text: 'Log In') }
    end

    describe "visiting the edit page" do
      before { visit edit_user_path(user) }
      it { should have_selector('title', text: 'Log In') }
    end

    describe "submitting to the update action" do
      before { put user_path(user) }
      specify { response.should redirect_to(login_path) }
    end

     describe "submitting a DELETE request to the Users#destroy action" do
      before { delete user_path(user) }
      specify { response.should redirect_to(root_path) }        
    end

....etc.....

  end
end

我是否需要为每个想要测试的控制器指定所有7条休息路由?看起来效率很低。有没有办法说“在访问之前任何用户路由响应应该重定向到login_path”?

1 个答案:

答案 0 :(得分:0)

在尝试列出并测试所有应用程序路由中是否有500个错误时,我也遇到了类似的问题,我不想手动逐个手动添加每个路由(我有150个左右)。

我在命令rake routes中镜像了代码,并使用ActionDispatch::Routing::RouteWrapperRails.application.routes.routes列出了它们。

包装器提供了一种简单的方法来检查路由的控制器,动词和动作。 从那里开始,您只需要过滤要检查的路由并在对每个路由进行测试时对其进行迭代。

context 'all routes' do
    let(:all_app_routes) do
      Rails.application.routes.routes.collect do |route|
        ActionDispatch::Routing::RouteWrapper.new route 
      end.reject(&:internal?)
    end
    context 'in the Users controller' do
      let(:users_controller_routes) do
        all_app_routes.select { |route| route.controller == 'users' }
      end

      it 'all routes should redirect to login' do
        users_controller_routes.each do |route|
          begin
            # reconstruct the path with the route name
            # I did not test the line below, I personnaly kept using get('/' << route.name) as my case was to test the index pages only.
            # but you get the idea: call your http route below (http.rb, net/http, ...)
            send(route.verb, '/' << route.name)
            # will produce something like : get('/users/')

            # test it does indeed redirect
            expect(response.status).to eq(302)
            expect(response.body).to include?('my_redirect_location')

            # you could also continue further testing
            follow_redirect!
            expect(response.body).to include('<div id="login">')
          rescue Exception
            next
            # or fail test depending on what you want to check
            # I had the case of abstract method in controllers that raised exception
          end
        end
      end
    end
  end

我个人仅将此代码用于测试索引方法(select {|route| route.action =='index' }...),因为批量测试创建/销毁/新建/编辑被证明太困难了(每次都需要不同的参数)