Rails规范错误:预期有效吗?回归真实,变得虚伪

时间:2013-10-16 08:09:13

标签: ruby-on-rails ruby-on-rails-4 rspec-rails

我正在关注Michael Hartl的RoR教程,但在测试我的代码时遇到以下错误。我似乎无法弄清楚为什么我的对象没有传递为有效。

我的user.rb文件:

class User < ActiveRecord::Base

  before_save { |user| user.email = user.email.downcase }

  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
end

这是我的user_rspec.rb:

    require 'spec_helper'

describe User do

  before { @user = User.new(name: "bobo", email: "user@example.com")  }

  subject { @user }

  it { should respond_to(:name) }
  it { should respond_to(:email) }

  it { should be_valid }

  describe "when name is not present" do
    before { @user.name = " "}

    it { should_not be_valid}
  end

  describe "when email is not present" do
    before { @user.email = " "}

    it { should_not be_valid}
  end

  describe "when name is too long" do
    before { @user.name = "a" * 51}

    it { should_not be_valid}
  end

  describe "when email format is invalid" do
    it "should be invalid" do
      addresses = %w[user@foo,com user_at_foo.org example-user@foo.]
      addresses.each do |invalid_address|
        @user.email = invalid_address
        @user.should_not be_valid
      end
    end
  end

  describe "when email format is valid" do
    it "should be valid" do 
      addresses = %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn]
      addresses.each do |valid_address|
        @user.email = valid_address
        @user.should be_valid
      end
    end
  end

  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

end

当我运行测试时,我收到以下错误:     故障:

  1) User 
     Failure/Error: it { should be_valid }
       expected valid? to return true, got false
     # ./spec/models/user_spec.rb:12:in `block (2 levels) in <top (required)>'

Finished in 0.21355 seconds
9 examples, 1 failure

Failed examples:

rspec ./spec/models/user_spec.rb:12 # User `

当我在rails控制台中运行user_with_same_email.errors时,我得到以下答案:

ruby-2.0.0-p247 :001 > user = User.new(name: "bobo", email: "user@example.com")
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at:     nil> 
ruby-2.0.0-p247 :002 > user_with_same_email =  user.dup
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at: nil> 
ruby-2.0.0-p247 :003 > user_with_same_email.valid?
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") =     LOWER('user@example.com') LIMIT 1
 => true 
ruby-2.0.0-p247 :004 > user_with_same_email.errors
 => #<ActiveModel::Errors:0x007fad6491f780 @base=#<User id: nil, name: "bobo", email:    "user@example.com", created_at: nil, updated_at: nil>, @messages={}> 
ruby-2.0.0-p247 :005 >

如您所见,错误未传递任何消息。

有人知道如何解决这个错误吗?

谢谢!

添加了:

当我尝试使用已保存的电子邮件保存用户时,似乎出现错误。

$ rails console --sandbox
Loading development environment in sandbox (Rails 4.0.0)
Any modifications you make will be rolled back on exit
ruby-2.0.0-p247 :001 > user = User.new(name: "bobo", email: "user@example.com")
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at:         nil> 
ruby-2.0.0-p247 :002 > user.save
   (0.1ms)  SAVEPOINT active_record_1
  User Exists (0.2ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") =     LOWER('user@example.com') LIMIT 1
  SQL (3.3ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES       (?, ?, ?, ?)  [["created_at", Wed, 16 Oct 2013 10:15:19 UTC +00:00], ["email",     "user@example.com"], ["name", "bobo"], ["updated_at", Wed, 16 Oct 2013 10:15:19 UTC +00:00]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
 => true 
    ruby-2.0.0-p247 :003 > user_with_same_email =  user.dup
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at: nil> 
ruby-2.0.0-p247 :004 > user_with_same_email.save
   (0.1ms)  SAVEPOINT active_record_1
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user@example.com') LIMIT 1
   (0.1ms)  ROLLBACK TO SAVEPOINT active_record_1
 => false 
ruby-2.0.0-p247 :005 > 

我不确定为什么会这样。我的验证不应该解决这个问题吗?

谢谢!

3 个答案:

答案 0 :(得分:0)

您传递的名称不超过50个字符,并且您的电子邮件与您制作的正则表达式相匹配。唯一剩下的就是电子邮件的唯一性。我打赌你没有在规格之间正确清理你的数据库。您可以通过将should be_valid规范扩展到此来确认吗?

it "is valid" do
  subject.valid?
  subject.errors.full_messages.should eq []
end

调用valid?将填充errors数组,然后规范将失败并显示错误消息。

如果已经收到电子邮件,请尝试使用database_cleaner https://github.com/bmabey/database_cleaner#rspec-example(您必须先将其添加到Gemfile才能使用。

答案 1 :(得分:0)

如前所述,@user.errors.messages的错误消息包含{:email=>["has already been taken"]}

您可以通过添加 spec_helper.rb (在RSpec.configure do |config|区块中)初步解决此问题:

# clears user table
config.before(:suite) do
  User.destroy_all
end

但我不相信这个解决方案。看来,用户在测试用例之后不会破坏自己。

答案 2 :(得分:0)

我的测试也失败了

  it { should be_Valid }

我的rails控制台会话(上图)user.valid为true

以下更正的测试

it { should be_valid }

大写'be_Valid'是问题