【问题标题】:Testing authentication with Sorcery and RSpec使用 Sorcery 和 RSpec 测试身份验证
【发布时间】:2016-07-09 06:49:14
【问题描述】:

在寻求帮助之前,我已经花了太长时间搞砸了。我似乎无法让 RSpec 和 Sorcery 很好地配合使用。我已经阅读了Integration testing with Sorcery 上的文档,并且可以正确发布登录操作,但我的测试仍然认为用户没有登录。

# spec/controllers/user_controller_spec
describe 'user access' do
    let (:user) { create(:user) }

    before :each do
      login_user(user[:email], user[:password])
    end

    it "should log in the user" do
      controller.should be_logged_in
    end

end

还有我的 login_user 方法

# spec/support/sorcery_login
module Sorcery
  module TestHelpers
    module Rails
      def login_user email, password
        page.driver.post(sessions_path, { email: email , password: password, remember_me: false })
      end
    end
  end
end

当我在生成的页面上使用它们时,会话控制器可以正确处理页面。我尝试输出 login_user 方法的结果,它似乎可以正确发布数据。如何通过测试保留此登录用户? before :each 块是否对此不起作用?我只是不确定它可能在哪里运行错误,而且我对测试/RSpec 还很陌生,所以我可能会遗漏一些明显的东西。如有任何帮助,我将不胜感激。

这是失败测试的输出:

1) UsersController user access should log in the user
    Failure/Error: controller.should be_logged_in
    expected logged_in? to return true, got false

【问题讨论】:

    标签: ruby-on-rails rspec sorcery


    【解决方案1】:

    我昨天刚刚经历了这个。如果有帮助,这就是我所做的。

    Sorcery 提供了一个测试助手 login_user,它依赖于可用的 @controller 对象。这在控制器规范中效果很好,但在集成测试中不起作用。因此集成测试中的解决方法是编写另一种方法(如您上面的方法)来模拟通过 HTTP 请求实际登录(本质上是模拟提交表单)。

    所以我的第一个想法是您应该尝试将您的方法重命名为 login_user_post 或其他不与内置测试助手冲突的名称。

    另一个潜在的问题是,在我看来,Sorcery 助手假定您的用户密码是“秘密”的。

    这是内置帮助程序的链接,因此您可以看到我在说什么:

    https://github.com/NoamB/sorcery/blob/master/lib/sorcery/test_helpers/rails.rb

    祝你好运 - 我真的很喜欢这颗宝石,除了这部分。实际上只有通过将 SO 帖子拼凑在一起才能完全解释。这是我使用的代码:

    集成助手

    module Sorcery
      module TestHelpers
        module Rails
          def login_user_post(user, password)
            page.driver.post(sessions_url, { username: user, password: password}) 
          end
    
          def logout_user_get
            page.driver.get(logout_url)
          end
        end
      end
    end
    

    集成规范(用户需要登录才能做事)

      before(:each) do
        @user = create(:user)
        login_user_post(@user.username, 'secret')
      end
    

    控制器规范(常规的 login_user 助手工作正常)

      before(:each) do
        @user = create(:user)
        login_user
      end
    

    请注意,如果您有一个密码为“secret”的@user 对象,则 login_user 不需要任何参数。

    【讨论】:

    • 完美,谢谢!看起来问题在于方法名称冲突。
    【解决方案2】:

    您是否尝试添加到 spec/spec_helpers。

    RSpec.configure do |config|
      # ...
      config.include Sorcery::TestHelpers::Rails::Controller
    end
    

    请注意,您需要包含Sorcery::TestHelpers::Rails::Controller,而不仅仅是Sorcery::TestHelpers::Rails

    然后您将能够从任何控制器规格中login_user,例如:

    describe CategoriesController do
    
      before do
        @user = FactoryGirl::create(:user)
      end
    
      describe "GET 'index'" do
        it "returns http success" do
          login_user
          get 'index'
          expect(response).to be_success
        end
      end
    end
    

    【讨论】:

      【解决方案3】:

      您传递密码的方式可能是错误的。此时可能已加密。在提供的示例中,我将首先尝试这样做:

      describe 'user access' do
          let (:user) { create(:user, password: 'secret') }
      
          before :each do
            login_user(user[:email], 'secret')
          end
      
          it "should log in the user" do
            controller.should be_logged_in
          end
      end
      

      【讨论】:

        【解决方案4】:

        这似乎记录得很差。上述解决方案对我不起作用。这是我如何让它工作的:

        检查您的sessions_url。确保它是正确的。另外,检查登录所需的参数。可能是emailusername等。

        module Sorcery
          module TestHelpers
            module Rails
              def login_user_post(email, password)
                page.driver.post(sessions_url, { email:email, password: password }) 
              end
            end
          end
        end
        

        RSpec 配置:

        config.include Sorcery::TestHelpers::Rails
        

        规范助手:

        def app
          Capybara.app
        end
        

        spec/controllers/protected_resource_spec.rb:

        describe UsersController do
          before do
            # Create user
        
            # Login
            response = login_user_post( user.email, :admin_password )
            expect( response.headers[ 'location' ]).to eq 'http://test.host/' 
            # I test for login success here. Failure redirects to /sign_in.
        
            @cookie = response.headers[ 'Set-Cookie' ]
          end
        
          specify 'Gets protected resource' do
            get protected_resource, {}, { cookie:@cookie }
            expect( last_response.status ).to eq 200
          end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-29
          • 2012-06-15
          • 2017-05-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多