【问题标题】:How to test after_sign_in_path_for(resource)?如何测试 after_sign_in_path_for(resource)?
【发布时间】:2011-07-12 00:26:13
【问题描述】:

我已经在我的 Rails 应用程序上设计了身份验证和注册设置。我正在使用after_sign_in_path_for()根据各种场景自定义用户登录时的重定向。

我要问的是如何测试这种方法?似乎很难隔离,因为它是在用户登录时由 Devise 自动调用的。我想做这样的事情:

describe ApplicationController do
  describe "after_sign_in_path_for" do
    before :each do
      @user = Factory :user
      @listing = Factory :listing
      sign_in @user
    end

    describe "with listing_id on the session" do
      before :each do
        session[:listing_id] = @listing.id
      end

      describe "and a user in one team" do
        it "should save the listing from the session" do
          expect {
            ApplicationController.new.after_sign_in_path_for(@user)
          }.to change(ListingStore, :count).by(1)
        end

        it "should return the path to the users team page" do
          ApplicationController.new.after_sign_in_path_for(@user).should eq team_path(@user.team)
        end
      end
    end
  end
end

但这显然不是这样做的方法,因为我只是得到一个错误:

 Failure/Error: ApplicationController.new.after_sign_in_path_for(@user)
 RuntimeError:
   ActionController::Metal#session delegated to @_request.session, but @_request is nil: #<ApplicationController:0x00000104581c68 @_routes=nil, @_action_has_layout=true, @_view_context_class=nil, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_request=nil, @_response=nil>

那么,我该如何测试这个方法呢?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 rspec devise rspec2


    【解决方案1】:

    奇怪的是,我今天很想知道这件事。这就是我想出的。我创建了 ApplicationController 的匿名子类。在这个匿名子类中,我将要测试的受保护方法公开为公共方法。然后我就直接测试了。

    describe ApplicationController do
      controller do
        def after_sign_in_path_for(resource)
            super resource
        end
      end
    
      before (:each) do
        @user = FactoryGirl.create(:user)
      end
    
      describe "After sigin-in" do
        it "redirects to the /jobs page" do
            controller.after_sign_in_path_for(@user).should == jobs_path
        end
      end
    
    end
    

    【讨论】:

    • 谢谢!你刚刚救了我另一个设计头痛
    • 非常感谢。我正在考虑这个,但对这个控制器一无所知。after_sign_in_path_for(@user).should == jobs_path
    【解决方案2】:

    类似的说明 - 如果您想在注册后测试重定向,您有两种选择。

    首先,您可以按照与上述类似的模式,非常直接地测试 RegistrationsController 中的方法:

    require 'spec_helper'
    
    describe RegistrationsController do
    
      controller(RegistrationsController) do
        def after_sign_up_path_for(resource)
            super resource
        end
      end
    
      describe "After sign-up" do
        it "redirects to the /organizations/new page" do
            @user = FactoryGirl.build(:user)
            controller.after_sign_up_path_for(@user).should == new_organization_path
        end
      end
    end
    

    或者,您可以采用更多集成测试的方法并执行以下操作:

    require 'spec_helper'
    
    describe RegistrationsController do
    
      describe "After successfully completing the sign-up form" do
    
        before do
            @request.env["devise.mapping"] = Devise.mappings[:user]
        end
    
        it "redirects to the new organization page" do
            post :create, :user => {"name" => "Test User", "email" => "test@example.com", "password" => "please"}
            response.should redirect_to(new_organization_path)
        end
      end
    end
    

    【讨论】:

      【解决方案3】:

      对于新手,我建议这样做:

      RSpec.describe ApplicationController, type: :controller do
        let(:user) { create :user }
      
        describe "After sing-in" do
          it "redirects to the /yourpath/ home page" do
            expect(subject.after_sign_in_path_for(user)).to eq(yourpath_root_path)
          end
        end
      end
      

      【讨论】:

      • 能否澄清一下“主题”是什么?
      • @Abdul-RahmanAhmad 'ApplicationController' 在 RSpec.describe ApplicationController 中。
      • 谢谢,知道了
      【解决方案4】:

      我最近通过 Google 找到了这个答案,并认为我会添加我的解决方案。我不喜欢接受的答案,因为它正在测试应用程序控制器上方法的返回值与测试应用程序的所需行为。

      我最终只是测试了创建新会话作为请求规范的调用。

      RSpec.describe "Sessions", type: :request do
          it "redirects to the internal home page" do
              user = FactoryBot.create(:user, password: 'password 123', password_confirmation: 'password 123')
              post user_session_path, params: {user: {email: user.email, password: 'password 123'}}
              expect(response).to redirect_to(internal_home_index_path)
          end
      end
      

      (Rails 5,设计 4,RSpec 3)

      【讨论】:

        【解决方案5】:
        context "without previous page" do
          before do
            Factory.create(:user, email: "junior@example.com", password: "123456", password_confirmation: "123456")
            request.env["devise.mapping"] = Devise.mappings[:user]
            post :create, user: { email: "junior@example.com", password: "123456" }
          end
        end 
        
          it { response.should redirect_to(root_path) }
        context "with previous page" do
          before do
            Factory.create(:user, email: "junior@example.com", password: "123456", password_confirmation: "123456")
            request.env["devise.mapping"] = Devise.mappings[:user]
            request.env['HTTP_REFERER'] = 'http://test.com/restaurants'
            post :create, user: { email: "junior@example.com", password: "123456" }
          end
        
          it { response.should redirect_to("http://test.com/restaurants") }
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-27
          • 2014-09-08
          • 2015-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多