55

私はここ数年Railsで遊んでいて、本番環境にあるいくつかの無難なアプリを作成しました。私はいつもテストをすることを避けてきました、そして私はそれを修正することに決めました。私は、すでに稼働しているが絶えず改訂されている作業のために書いたアプリのいくつかのテストを書き込もうとしています。変更を加えると問題が発生するのではないかと心配しているので、いくつかのテストを実行してもらいたいと思います。私はRSpecの本を読み、いくつかのスクリーンキャストを見ましたが、始めるのに苦労しています(実際にそれを行った後でしか理解できないようなものだと思います)。

ReportsControllerの簡単なテストとなるものを書き込もうとしています。私のアプリの問題は、ほとんどすべてが認証レイヤーの背後にあることです。ログインしていない場合は何も機能しないため、単純なgetリクエストを送信する前に、ログインをシミュレートする必要があります(ただし、ログインなしでは何も機能しないことを確認するために、いくつかのテストを作成する必要があります。それは後で)。

RSpec、Capybara、FactoryGirl、Guardを使用してテスト環境をセットアップしました(どのツールを使用するかわからなかったため、Railscastの提案を使用しました)。これまでテストを作成してきた方法は、FactoryGirlでそのようなユーザーを作成することです。

FactoryGirl.define do
  sequence(:email) {|n| "user#{n}@example.com"}
  sequence(:login) {|n| "user#{n}"}
  factory :user do
    email {FactoryGirl.generate :email}
    login {FactoryGirl.generate :login}
    password "abc"
    admin false
    first_name "Bob"
    last_name "Bobson"
  end
end

そして、そのように私のテストを書きます。

require 'spec_helper'

describe ReportsController do
  describe "GET 'index'" do
    it "should be successful" do
      user = Factory(:user)
      visit login_path
      fill_in "login", :with => user.login
      fill_in "password", :with => user.password
      click_button "Log in"
      get 'index'
      response.should be_success
    end
  end
end

これはそのように失敗します。

  1) ReportsController GET 'index' should be successful
     Failure/Error: response.should be_success
       expected success? to return true, got false
     # ./spec/controllers/reports_controller_spec.rb:13:in `block (3 levels) in <top (required)>'

興味深いことに、テストをに変更すると、テストにresponse.should be_redirect合格します。これは、その時点まですべてが機能しているが、ログインが認識されていないことを示しています。

だから私の質問は、このログインを機能させるために何をしなければならないかということです。FactoryGirlクレデンシャルに一致するユーザーをデータベースに作成する必要がありますか?もしそうなら、ここでのFactoryGirlのポイントは何ですか(そして私もそれを使用する必要があります)?テスト環境でこの偽のユーザーを作成するにはどうすればよいですか?私の認証システムは非常に単純な自作のシステムです(Railscastsエピソード250に基づく)。このログイン動作は、おそらくほとんどすべてのテストで複製する必要があるので、コードで一度実行して、どこにでも適用するにはどうすればよいですか?

これは大きな質問だと思いますので、ご覧いただきありがとうございます。

4

5 に答える 5

48

答えは、認証の実装によって異なります。通常、ユーザーがログインするときに、そのユーザーを記憶するようにセッション変数を設定します。たとえば、session[:user_id]。コントローラは、へのログインをチェックし、before_filterそのようなセッション変数が存在しない場合はリダイレクトします。私はあなたがすでにこのようなことをしていると思います。

これをテストで機能させるには、ユーザー情報をセッションに手動で挿入する必要があります。これが私たちが仕事で使うものの一部です:

# spec/support/spec_test_helper.rb
module SpecTestHelper   
  def login_admin
    login(:admin)
  end

  def login(user)
    user = User.where(:login => user.to_s).first if user.is_a?(Symbol)
    request.session[:user] = user.id
  end

  def current_user
    User.find(request.session[:user])
  end
end

# spec/spec_helper.rb
RSpec.configure do |config|
  config.include SpecTestHelper, :type => :controller
end

これで、コントローラーの例のいずれかで、login(some_user)そのユーザーとしてのログインをシミュレートするために呼び出すことができます。


また、このコントローラーテストで統合テストを行っているようです。原則として、コントローラーテストは、次のような個々のコントローラーアクションへの要求のみをシミュレートする必要があります。

it 'should be successful' do
  get :index
  response.should be_success
end

これは特に、一連のコントローラーテストで必要な単一のコントローラーアクションをテストします。次に、Capybara / Cucumberを使用して、フォーム、ビュー、およびコントローラーのエンドツーエンドの統合テストを行うことができます。

于 2012-04-12T10:43:00.143 に答える
13

spec / support / controller_helpers.rbにヘルパーファイルを追加し、以下のコンテンツをコピーします

module ControllerHelpers
    def sign_in(user)
      if user.nil?
        allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
        allow(controller).to receive(:current_user).and_return(nil)
      else
        allow(request.env['warden']).to receive(:authenticate!).and_return(user)
        allow(controller).to receive(:current_user).and_return(user)
      end
    end
  end

次に、 spec/rails_helper.rbまたはspec/spec_helper.rb ファイルに次の行を追加します

require 'support/controller_helpers'

RSpec.configure do |config|

    config.include Devise::TestHelpers, :type => :controller
    config.include ControllerHelpers, :type => :controller

  end

これで、コントローラーの仕様ファイルに追加されます。

describe  "GET #index" do

    before :each do        
        @user=create(:user)
        sign_in @user
    end
      ...
end

公式リンクを考案する

于 2016-04-12T09:20:03.970 に答える
2

@Brandanの回答を機能させることができなかったので、それとこの投稿に基づいて、私はこの解決策に到達しました:

# spec/support/rails_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Add this at top of file

...

include ControllerMacros # Add at bottom of file

# spec/support/controller_macros.rb
module ControllerMacros

  def login_as_admin
    admin = FactoryGirl.create(:user_admin)
    login_as(admin)
  end

  def login_as(user)
    request.session[:user_id] = user.id
  end

end

次に、テストで次を使用できます。

it "works" do
  login_as(FactoryGirl.create(:user))
  expect(request.session[:user_id]).not_to be_nil
end
于 2016-04-04T20:31:29.240 に答える
1

機能テストでユーザーにログインする最も簡単な方法は、Wardenのヘルパー#login_asを使用することです。

login_as some_user
于 2017-11-06T20:56:41.033 に答える
0

Deviseを使用しない場合:

spec/rails_helper.rb

require_relative "support/login_helpers"

RSpec.configure do |config|
  config.include LoginHelpers
end

spec/support/login_helpers.rb

module LoginHelpers
  def login_as(user)
    post "/session", params: { session: { email: user.email, password: "password" } }
  end
end

とスペックで:

login_as(user)
于 2021-01-09T19:28:49.390 に答える