2

User モデルをテストし、FactoryGirl がどのように機能するかを調べています。user_spec.rbでこれを行うと:

before(:each) do
  @user = User.new(username: 'ExampleUser', email: 'user@example.com', timezone: 'Eastern Time (US & Canada)', password: 'example')
end

すべてが合格しますが、もしそうなら:

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

ユーザーのユーザー名と電子メールが既に使用されているかどうかを確認するテストに失敗します。

1) User when username is already taken
     Failure/Error: it { should_not be_valid }
       expected valid? to return false, got true
     # ./spec/models/user_spec.rb:151:in `block (3 levels) in <top (required)>'

  2) User when email address is already taken
     Failure/Error: it { should_not be_valid }
       expected valid? to return false, got true
     # ./spec/models/user_spec.rb:142:in `block (3 levels) in <top (required)>'

Finished in 1.8 seconds
29 examples, 2 failures

これらはテストです:

  describe 'when email address is already taken' do
    before do
      user_with_same_email = @user.dup
      user_with_same_email.email = @user.email.upcase
      user_with_same_email.save
    end
    it { should_not be_valid }
  end

  describe 'when username is already taken' do
    before do
      user_with_same_username = @user.dup
      user_with_same_username.username = @user.username.upcase
      user_with_same_username.save
    end
    it { should_not be_valid }
  end

誰か説明できますか?FactoryGirl はUser.new、私の最初の例である のように使用できると考えていました。

4

2 に答える 2

1

通常、Factory Girl を使用してフィールドをテストする場合は、 sequencevalidates_uniqueness_ofを使用するのが最適です。

シーケンスを使用すると、 でレコードを作成するたびFactoryGirl.create(:user)に、ユーザー名は常に一意になります。これにより、競合する値を手動で修正することなく、データベース内の「実際の」レコードを操作できます。

factory :user do
  sequence :username do |n}
    "user_#{n}"
  end
end

注:データベースに追加されていないレコードをテストするという考えは好きではありません。それが問題になる確固たる理由は思いつきません。私が考えることができる唯一の問題は、関連付けをテストできないという事実です。


あなたの質問で私が気づいていることは、beforeブロックを使用してインスタンス変数を作成することです。RSpec には、let必要なときに変数を作成するというメソッドがあります。

これにより、user_spec.rbファイルがそのように機能します。

describe User do
  let(:user) { create(:user, :first_name => "John", :last_name => "Doe") }

  it "should get full name" do
    user.full_name.should == "John Doe"
  end
end

letitブロックで使用されているかどうかに関係なく、変数を作成する bang メソッドもあります。

于 2012-09-14T02:40:37.010 に答える
1

FactoryGirl.create実際にレコードを作成しUser.newますが、モデルをインスタンス化するだけで、実際にはレコードを保存しません。

モデルをインスタンス化するだけの場合は、次を使用する必要がありますFactoryGirl.build

before(:each) do
  @user = FactoryGirl.build(:user)
end

詳細については、ドキュメントを参照してください。

したがって、現在のコードで起こっていると思うのは、でユーザーを作成するとFactoryGirl.create、実際には検証の問題なしでレコードが保存されるということです (複製がまだ作成されていないため)。で同じ電子メールでユーザーを保存すると、user_with_same_email.save実際にはそのユーザーは保存されませんが、それは表示されません。次に、元のユーザーが有効かどうかを確認すると、複製を作成しようとする (そして失敗する) 前に既に保存しているため、「はい」と表示されます。

わかる?とにかくに切り替えるだけでFactoryGirl.build、両方のテストに合格するはずです。

于 2012-09-13T23:43:02.093 に答える