【问题标题】:Rails/Rspec Make tests pass with http basic authenticationRails/Rspec 使用 http 基本身份验证使测试通过
【发布时间】:2010-09-22 11:25:40
【问题描述】:

这是我在应用程序控制器文件 (application_controller.rb) 中的 http 基本身份验证

before_filter :authenticate

protected

def authenticate
  authenticate_or_request_with_http_basic do |username, password|
    username == "username" && password == "password"  
  end
end

以及我家控制器的索引操作的默认测试(spec/controllers/home_controller_spec.rb)

require 'spec_helper'

describe HomeController do

describe "GET 'index'" do
  it "should be successful" do
    get 'index'
    response.should be_success
  end
end

由于身份验证方法,测试未运行。我可以评论“before_filter :authenticate”来运行它们,但我想知道是否有办法让它们与该方法一起工作。

谢谢!

【问题讨论】:

  • 从 Rails 6 开始,看起来this answer 是可行的。

标签: ruby-on-rails rspec http-authentication


【解决方案1】:

更新(2013 年):Matt Connolly 提供了一个 GIST,它也适用于请求和控制器规范:http://gist.github.com/4158961


如果您有许多测试要运行并且不想每次都包含它(DRYer 代码),则另一种方法是:

创建 /spec/support/auth_helper.rb 文件:

module AuthHelper
  def http_login
    user = 'username'
    pw = 'password'
    request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
  end  
end

在您的测试规范文件中:

describe HomeController do
  render_views

  # login to http basic auth
  include AuthHelper
  before(:each) do
    http_login
  end

  describe "GET 'index'" do
    it "should be successful" do
      get 'index'
      response.should be_success
    end
  end

end

信用here

【讨论】:

  • 它显示请求对我来说是零。知道如何解决吗?
  • 对于请求规范,您可以有多个请求,因此requestnil。相反,您需要创建一个 env 哈希 env = {},在您的 http_login 方法中更新它,然后像 get '/', {}, env 一样显式传入 env。
  • 扩展上述内容,适用于请求和控制器规范:gist.github.com/4158961
  • +1 来自 Matt Connolly 的要点;它解决了我的问题,而其他什么都没有。顺便说一句,我尝试使用 Rack::Test 授权方法 - 没有用。
  • 我得到失败/错误:@request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials("test_access1") NoMethodError: undefined method `env' for nil:NilClass when我尝试使用这个..为什么?
【解决方案2】:

抱歉我没找够,解决方法好像是这样的:

describe "GET 'index'" do
  it "should be successful" do
    @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("username:password")
    get 'index'
    response.should be_success
  end
end

【讨论】:

    【解决方案3】:

    一些答案​​建议设置request.env,这是不安全的,因为请求可以是nil,你最终会得到private method env' called for nil:NilClass,尤其是在使用rspec -e 运行单个测试时

    正确的做法是:

    def http_login
      user = 'user'
      password = 'passw'
      {
        HTTP_AUTHORIZATION: ActionController::HttpAuthentication::Basic.encode_credentials(user,password)
      }
    end
    
    get 'index', nil, http_login
    
    post 'index', {data: 'post-data'}, http_login
    

    【讨论】:

    • 谢谢,这是我使用 Capybara 进行系统测试的唯一方法。
    【解决方案4】:

    使用 Rspec 测试 Grape API 时,以下语法有效

            post :create, {:entry => valid_attributes}, valid_session
    

    valid_session 在哪里

    {'HTTP_AUTHORIZATION' => credentials}
    

    credentials = ActionController::HttpAuthentication::Token.encode_credentials("test_access1")
    

    【讨论】:

      【解决方案5】:

      对于我来说,使用 Rails 6,我需要 rspec 获取方法的关键字参数,例如 ..get route, params: params, headers: headers

      Auth Helper 方法

      module AuthHelper
        def headers(options = {})
          user = ENV['BASIC_AUTH_USER']
          pw = ENV['BASIC_AUTH_PASSWORD']
      
          { HTTP_AUTHORIZATION: ActionController::HttpAuthentication::Basic.encode_credentials(user,pw) }
        end
        def auth_get(route, params = {})
          get route, params: params, headers: headers
        end
      end
      

      rspec 请求测试。

      describe HomeController, type: :request do    
        include AuthHelper
      
        describe "GET 'index'" do
          it "should be successful" do
            auth_get 'index'
            expect(response).to be_successful
          end
        end
      
      end
      

      【讨论】:

        【解决方案6】:

        这些是控制器和请求规范的绝佳解决方案。

        对于使用 Capybara 的功能测试,以下是使 HTTP 基本身份验证工作的解决方案:

        spec/support/when_authenticated.rb

        RSpec.shared_context 'When authenticated' do
          background do
            authenticate
          end
        
          def authenticate
            if page.driver.browser.respond_to?(:authorize)
              # When headless
              page.driver.browser.authorize(username, password)
            else
              # When javascript test
              visit "http://#{username}:#{password}@#{host}:#{port}/"     
             end
          end
        
          def username
            # Your value here. Replace with string or config location
            Rails.application.secrets.http_auth_username
          end
        
          def password
            # Your value here. Replace with string or config location
            Rails.application.secrets.http_auth_password
          end
        
          def host
            Capybara.current_session.server.host
          end
        
          def port
            Capybara.current_session.server.port
          end
        end
        

        然后,在您的规范中:

        feature 'User does something' do
          include_context 'When authenticated'
        
          # test examples
        end
        

        【讨论】:

        【解决方案7】:

        我的解决方案:

        stub_request(method, url).with(
          headers: { 'Authorization' => /Basic */ }
        ).to_return(
          status: status, body: 'stubbed response', headers: {}
        )
        

        使用 gem webmock

        您可以通过更改加强验证:

        /Basic */ -> "Basic #{Base64.strict_encode64([user,pass].join(':')).chomp}"
        

        URL - 可以是正则表达式

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-30
          • 2015-05-13
          • 1970-01-01
          相关资源
          最近更新 更多