私はここ数年、Railsで遊んでいて、実稼働中のいくつかのパス可能なアプリを作成しました。しかし、テストを行うことは常に避け、修正することにしました。すでに稼働しているが、常に改訂されている作業用に作成したアプリのテストを作成しようとしています。変更があると問題が発生する可能性があるので、テストを実行する必要があります。 RSpecの本を読み、いくつかのスクリーンキャストを見ましたが、始めるのに苦労しています(実際にやった後にしか理解できないようなものだと思います)。
ReportsControllerの簡単なテストとなるものを書き込もうとしています。私のアプリの問題は、ほとんどすべてが認証レイヤーの背後にあることです。ログインしていない場合は何も機能しないので、単純なgetリクエストを送信する前にログインをシミュレートする必要があります(ただし、ログインなしでは何も機能しないことを確認するためのテストを作成する必要があると思いますが、後で)。
RSpec、Capybara、FactoryGirl、およびGuardを使用してテスト環境をセットアップしました(使用するツールが不明なため、Railscastsの提案を使用しました)。これまでにテストを記述してきた方法は、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 episode 25 に基づいています)。このログイン動作は、ほとんどすべてのテストで複製する必要がありますが、コードで一度実行してどこにでも適用するにはどうすればよいですか?
これは大きな質問だと思いますので、ご覧いただきありがとうございます。
答えは、認証の実装によって異なります。通常、ユーザーがログインすると、セッション変数を設定して、そのユーザーを記憶します(_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を使用して、フォーム、ビュー、コントローラーのエンドツーエンドの統合テストを実行できます。
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
@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
機能テストでユーザーとログインする最も簡単な方法は、Wardenの helper #login_as を使用することです
login_as some_user