Ruby on rails Rails/Rspec使用http基本身份验证使测试通过

Ruby on rails Rails/Rspec使用http基本身份验证使测试通过,ruby-on-rails,rspec,http-authentication,Ruby On Rails,Rspec,Http Authentication,这里是应用程序控制器文件(application_controller.rb)中的http基本身份验证 以及my home控制器索引操作的默认测试(spec/controllers/home\u controller\u spec.rb) 由于身份验证方法,测试未运行。我可以评论“before_filter:authenticate”来运行它们,但我想知道是否有办法让它们与该方法一起工作 谢谢大家! 很抱歉,我没有寻求足够的解决方案,解决方案似乎如下: describe "GET 'index'

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

以及my home控制器索引操作的默认测试(spec/controllers/home\u controller\u spec.rb)

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


谢谢大家!

很抱歉,我没有寻求足够的解决方案,解决方案似乎如下:

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
更新(2013):马特·康诺利(Matt Connolly)提供了一个也适用于请求和控制器规格的要点:


另一种方法是,如果要运行许多测试,并且不希望每次都包含这些测试(代码):

创建/spec/support/auth\u 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
在测试规范文件中:

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

Credit

当使用Rspec测试grapeapi时,以下语法有效

        post :create, {:entry => valid_attributes}, valid_session
有效的_会话在哪里

{'HTTP_AUTHORIZATION' => credentials}


这些都是控制器和请求规格的优秀解决方案

对于使用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

一些答案建议设置
request.env
,这是不安全的,因为request可以是
nil
,您最终会得到调用nil:NilClass的
private method env',特别是在使用
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
我的解决方案:

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-可以是正则表达式

它显示请求对我来说为零。知道如何解决问题吗?对于请求规范,您可以有多个请求,因此
request
nil
。相反,您需要创建一个env hash
env={}
,在您的http_登录方法中更新它,然后像
get'/',{},env
那样显式地传入env;它解决了我的问题,而其他什么都没有。顺便说一句,我尝试使用Rack::Test AUTHORIZATION方法-不起作用。我得到失败/错误:@request.env['HTTP_AUTHORIZATION']=ActionController::HttpAuthentication::Token.encode_凭据(“Test_access1”)命名错误:尝试使用此方法时,未定义nil:NilClass的方法'env'。。为什么?非常有用!:)在Chrome、IE和Safari中不起作用(至少)谢谢,这是我使用Capybara进行系统测试的唯一有效方法。
/Basic */ -> "Basic #{Base64.strict_encode64([user,pass].join(':')).chomp}"