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
...

现在每个测试都像以前一样通过,除了一个:

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(您在顶部有“描述用户”,因此除非您指定其他内容,否则这是默认设置)。

您想检查 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

看起来您可能正在做(或参考)Michael Hartl 的Rails Tutorial。这是我的代码对于您正在做的事情的样子,所以我希望它可以使用:

规格/模型/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/factories.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 答案帮助我理解。

规格/模型/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 回答