Michael Hartl のRuby on Rails Tutorialの8.5 章の演習 2を実行しようとしています。演習は次のとおりです。
セクション 8.3.3 の例に従って、ユーザーおよび認証リクエストの仕様 (つまり、現在 spec/requests ディレクトリにあるファイル) を確認し、spec/support/utilities.rb でユーティリティ関数を定義して、テストを実装から分離します。追加クレジット: サポート コードを個別のファイルとモジュールに整理し、仕様ヘルパー ファイルにモジュールを適切に含めることですべてが機能するようにします。
例 8.3.3: utility.rb
include ApplicationHelper
def valid_signin(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
RSpec::Matchers.define :have_error_message do |message|
match do |page|
page.should have_selector('div.alert.alert-error', text: message)
end
end
定義されvalid_signin(user)
た関数は次のブロックで使用され、正常にauthentication_pages_spec.rb
動作します。
describe "with valid information" do
let(:user){FactoryGirl.create(:user)}
before { valid_signin(user) }
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
したがって、この例では、独自の名前付きの作成に取り掛かりましたvalid_signup(user)
:
def valid_signup(user)
fill_in "Name", with: user.name
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Confirmation", with: user.password_confirmation
end
このブロックを次のuser_pages_spec.rb
ように使用しています。
describe "with valid information" do
let(:user){FactoryGirl.create(:user)}
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email(user.email) }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
うまくいきません。Spor/Guard は次のエラーを報告します。
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: expect { click_button submit }.to change(User, :count).by(1)
count should have been changed by 1, but was changed by 0
# ./spec/requests/user_pages_spec.rb:46:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
3) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
4) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
valid_signup(user)
エラーは、私の関数の user.name がutilities.rb
定義されていないことを示唆しているようですが、その理由はわかりません。Guard を数回再起動rake db:test:prepare
し、テスト データベース (postgresql を使用) が正常であることを確認しました。
これが完全を期すための私のfactories.rb
ものです:
FactoryGirl.define do
factory :user do
name "Example User"
email "user@example.com"
password "foobar"
password_confirmation "foobar"
end
end
テスト スイートをさらに分離しようとする前に、このエラーを解決し、さらに重要なこととして、その理由を理解したいと思います。
編集
私はあなたのヒントを試し、関数user_pages_spec.rb
を次のように編集しました:
describe "with valid information" do
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email('user@example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
関数から削除let(:user){FactoryGirl.create(:user)}
したので、関数で作成されたユーザーがなくなったと推測したため、変数が FactoryGirl によって埋められなくなっvalid_signup(user)
たように定義する必要がありました。user
valid_signup
def valid_signup(user)
fill_in "Name", with: "Example User"
fill_in "Email", with: "user@example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
これは機能せず、次のエラーが発生しました。
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method user' for #<RSpec::Core::ExampleGroup::Nested_5::Nested_3::Nested_2:0x007fdafc5088c0>
# ./spec/requests/user_pages_spec.rb:42:in
block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in
block (5 levels) in '
valid_signup(user)
また、以前と同じ方法でテストを実行しようとしました( user.name, user.email, user.password, user.password_confirmation
、どちらも機能せず、エラーが発生しました:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method `user' for #
# ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in `block (5 levels) in '
次に、変数をuser_pages_spec.rb
:に渡さbefore { valid_signup() }
ず、関数 in に変数を渡さずに実行してみましたutilities.rb
:
def valid_signup()
fill_in "Name", with: "Example User"
fill_in "Email", with: "user@example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
これは以下を返しました:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method `user' for #
# ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in `block (5 levels) in '
まだ答えには近づいていません。私は簡単なことを見落としているかもしれません。何の手がかりもありません。しかし、私が最初にしたことは間違っていました。FactoryGirl は変数を作成する方法だと思っただけで、実際にテスト データベースに何かを行うことを知りませんでした。