0

編集

質問への回答を使用して、テストを次のように変更しました。これは正しくテストされ、合格します。

describe "when email is already taken" do
  let(:user_with_same_email) { @user.dup }
  before do
    user_with_same_email.email.upcase!
    user_with_same_email.save
  end

  it { user_with_same_email.should_not be_valid }
end

注:この質問に対する選択された回答のように、変数がブロック内で単純に複製された場合let(:user_with_same_email) { @user.dup }、変数を見つけることができないため、使用しないとテストが失敗します。user_with_same_emailbefore


Userモデルと、モデルの属性に対するさまざまな検証を含むテストファイルuser_spec.rbがあります。User

以前は、モデルuser_spec.rbをテストするためにファイルの先頭に次のように書いていました。User

describe User do

  before do
  @user = User.new(name: "Example User", email: "user@example.com",
                 password: "foobar88", password_confirmation: "foobar88")
end
...

このモデルの作成をに移動したかったFactoryGirlので、factories.rbファイルを作成しました。

FactoryGirl.define do
  factory :user do
    name "foo"
    email { "#{name}@example.com" }
    password "foobar99"
    password_confirmation "foobar99"
  end
end

その後、変更しましたuser_spec.rb

describe User do

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

これで、1つを除いて、すべてのテストが以前と同じように合格します。

describe "when email 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

`FactoryGirlがメールの一意性の検証をスキップしない限り、ここで何が問題になっているのか理解できません。

私のUserモデル検証コード:

class User < ActiveRecord::Base

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i unless const_defined?(:VALID_EMAIL_REGEX)

  has_secure_password
  attr_accessible :name, :email, :password, :password_confirmation

  has_many :programs

  before_save { self.email.downcase! }

  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
4

2 に答える 2

3

問題は、{should_not be_valid}と言うと、RSpecが件名をチェックすることです。この場合、件名はUser.newです(上部に「describeUser」があるため、他に何かを指定しない限り、これがデフォルトです)。

代わりに、user_with_same_emailの有効性を確認する必要があります。

編集: これを試してみてください、私はそれがうまくいくかもしれないと思います:

describe "when email 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 { @user_with_same_email.should_not be_valid }
end
于 2012-07-07T21:16:51.837 に答える
2

おそらくあなたはマイケル・ハートルのRailsチュートリアルをやっている(または参照している)ようです。これが私のコードがあなたがしていることに対してどのように見えるかです、それで私はそれが役に立つことができることを望みます:

spec / models / user_spec.rb

describe User do

  let(:user) { valid_user }
  subject { user }

  # ...

  context "when email address is already taken" do
    before { save_user(user) }
    it { should_not be_valid }
  end

  # ...
end

spec / support / Utilities.rb(特定のユーザーを作成するため)

def valid_user
  User.new(name:     "Example User", 
           email:    "user@example.com",
           password: "foobar", 
           password_confirmation: "foobar")
end

# ...

def save_user(user)
  user_with_same_email = user.dup
  user_with_same_email.email.upcase!
  user_with_same_email.save
end

参考:spec / factorys.rb(古いランダムユーザーを作成するため)

FactoryGirl.define do
  factory :user do
    sequence(:name)  { |n| "Person #{n}" }
    sequence(:email) { |n| "person_#{n}@example.com" }
    password "foobar"
    password_confirmation "foobar"

    # ...
  end
  # ...
end

更新:同じ問題の概要を説明するこのStackOverflowの回答で探していた回答を見つけました。私も自分のコードでそれをテストしました、そしてそれは私のために働きました。

更新2:コードも変更しました。FactoryGirl.buildユーザーは必要だが、データベースに保存したくない場合に使用します。 このStackOverflowの回答は、私が理解するのに役立ちました。

spec / models / user_spec.rb

describe User do

  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  # ...

  context "when email address is already taken" do
    let(:user_with_same_email) do
      FactoryGirl.build(:user, email: user.email)
    end

    subject { user_with_same_email }

    before do
      user_with_same_email.email.upcase!
      user_with_same_email.save
    end

    it { should_not be_valid }
  end
  # ...
end

この質問をしていただきありがとうございます。私自身のコードで行うための思考とリファクタリングのための食べ物をくれました。

于 2012-07-07T21:41:54.007 に答える