简体   繁体   English

Ruby on Rails rspec唯一性测试莫名其妙地失败

[英]Ruby on Rails rspec uniqueness test failing inexplicably

I have a suite of test for my @user model (following mhartl's tutorial) but inexplicably my test for email uniqueness has started failing mysteriously 我有一个针对@user模型的测试套件(遵循mhartl的教程),但莫名其妙地,我对电子邮件唯一性的测试开始神秘地失败了

require 'spec_helper'

describe User do
  before { @user = User.new(name: "Someguy", email: "some@guy.com",
  password: "password", password_confirmation: "password")}
  subject {@user}

  it {should respond_to(:name)}
  it {should respond_to(:email)}
  it {should respond_to(:password_digest)}
  it {should respond_to(:password)}
  it {should respond_to(:password_confirmation)}
  it {should respond_to(:remember_token)}
  it {should respond_to(:authenticate)}

  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 = "h"*50)}
    it {should_not be_valid}
  end

  describe "when email format is invalid" do
    it "should be invalid" do
      addresses = %w[rubbishemail@foo,com rubbishuser_at_foo.org rubbish@user@.com]
      addresses.each do |i|
        @user.email = i
        expect(@user).not_to be_valid
      end
    end
  end

  describe "when email format is valid" do
    it "should be valid" do
        addresses = %w[hi@iamhere.com yo@yothisisme.com whatup@whatupdog.co.uk]
        addresses.each do |i|
            @user.email = i
            expect(@user).to be_valid
        end
    end
  end

  describe "when email is already taken" do
    it "should_not be valid" 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 password is blank" do
    before do
      @user = User.new(name: "Example User", email: "user@example.com",
                     password: " ", password_confirmation: " ")
    end
    it { should_not be_valid }
  end

  describe "when password is not the same as password_confirmation" do
    before {@user.password_confirmation = "mismatch"}
  end

  describe "with a password that's too short" do
    before { @user.password = @user.password_confirmation = "a" * 5 }
    it { should be_invalid }
  end

  describe "return value of authenticate method" do
    before { @user.save }
    let(:found_user) { User.find_by(email: @user.email) }

    describe "with valid password" do
      it { should eq found_user.authenticate(@user.password) }
    end

    describe "with invalid password" do
      let(:user_for_invalid_password) { found_user.authenticate("invalid") }

      it { should_not eq user_for_invalid_password }
      specify { expect(user_for_invalid_password).to be_false }
    end
  end

end 结束

The specific test that is failing is: 失败的特定测试是:

  describe "when email is already taken" do
    it "should_not be valid" 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

And the error I am getting is as follows: 我得到的错误如下:

    Failures:

  1) User when email is already taken should not be valid
     Failure/Error: it {should_not be_valid}
       expected #<User id: nil, name: "Someguy", email: "some@guy.com", created_at: nil, updated_at: nil, password_digest: "$2a$04$ijkjuSSyFBAaMsDQ5vOyFO2VBVKFfFuvy5ArvfcWdW4H...", remember_token: nil> not to be valid
     # ./spec/models/user_spec.rb:60:in `block (3 levels) in <top (required)>'

The problem doesn't seem to be with the user model itself since if I go to the console and try to manually reconstruct the test I get the expected result (user.valid? returns false after saving user.dup. 该问题似乎与用户模型本身无关,因为如果我转到控制台并尝试手动重建测试,则会得到预期的结果(user.valid?保存user.dup后返回false。

    2.0.0-p247 :007 > user = User.new(name: "Someguy", email: "some@guy.com", password: "happiness", password_confirmation: "happiness")
 => #<User id: nil, name: "Someguy", email: "some@guy.com", created_at: nil, updated_at: nil, password_digest: "$2a$10$iGXz/r/RsiLKtNydXKft/en3KL.zT1B/bD5VehfNhiUj...", remember_token: nil> 
2.0.0-p247 :008 > user2 = user.dup
 => #<User id: nil, name: "Someguy", email: "some@guy.com", created_at: nil, updated_at: nil, password_digest: "$2a$10$iGXz/r/RsiLKtNydXKft/en3KL.zT1B/bD5VehfNhiUj...", remember_token: nil> 
2.0.0-p247 :009 > user2.save
   (0.2ms)  begin transaction
  User Exists (0.2ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('some@guy.com') LIMIT 1
Binary data inserted for `string` type on column `password_digest`
  SQL (3.9ms)  INSERT INTO "users" ("created_at", "email", "name", "password_digest", "updated_at") VALUES (?, ?, ?, ?, ?)  [["created_at", Sun, 20 Oct 2013 00:30:45 UTC +00:00], ["email", "some@guy.com"], ["name", "Someguy"], ["password_digest", "$2a$10$iGXz/r/RsiLKtNydXKft/en3KL.zT1B/bD5VehfNhiUj0i2Xl0YiK"], ["updated_at", Sun, 20 Oct 2013 00:30:45 UTC +00:00]]
   (2.2ms)  commit transaction
 => true 
2.0.0-p247 :010 > user.valid?
  User Exists (0.4ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('some@guy.com') LIMIT 1
 => false 
2.0.0-p247 :011 > 

The code for the user model is below (although I do not think this is the problem?) 用户模型的代码如下(尽管我不认为这是问题所在?)

class User < ActiveRecord::Base
    before_save {self.email = email.downcase }
    validates(:name, {presence: true, length: {maximum: 49}})
    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})
    validates :password, length: { minimum: 6 }
    has_secure_password
end

I tried to identify where the test was failing by adding some puts into the test as follows 我尝试通过在测试中添加一些put来确定测试失败的地方

  describe "when email is already taken" do
    it "should_not be valid" do
        user_with_same_email = @user.dup
      puts @user.email+"hello"
        user_with_same_email.email = @user.email.upcase
        did_save = user_with_same_email.save
      puts did_save
        end
    it {should_not be_valid}
    end

and the result when running the test suite is: 运行测试套件时的结果是:

    ..........some@guy.comhello
true
.F........

Failures:

  1) User when email is already taken should not be valid
     Failure/Error: it {should_not be_valid}
       expected #<User id: nil, name: "Someguy", email: "some@guy.com", created_at: nil, updated_at: nil, password_digest: "$2a$04$UKI8WbXbK9QnG7BF6AGnpeteaM8llDB/NMUj07UMTYsX...", remember_token: nil> not to be valid
     # ./spec/models/user_spec.rb:62:in `block (3 levels) in <top (required)>'

Finished in 0.17485 seconds
20 examples, 1 failure

Failed examples:

rspec ./spec/models/user_spec.rb:62 # User when email is already taken should not be valid

from the above it looks as though the @user.email object is nil! 从上面看来,@ user.email对象似乎为nil! But this can't be the whole story because @user.dup is successfully assigning the correct values... 但这不是全部,因为@ user.dup成功分配了正确的值...

Can anyone explain why the test is failing? 谁能解释为什么测试失败?

THanks, 谢谢,

I think you need to use a before block here as opposed to two it blocks (the first block contains no test, and the second block will not have had the duplicate user saved before it is run). 我认为您需要before这里使用一个before块,而不是两个it块(第一个块不包含测试,第二个块在运行之前不会保存重复的用户)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM