0

@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

終わり

失敗している特定のテストは次のとおりです。

  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

そして、私が得ているエラーは次のとおりです。

    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)>'

コンソールに移動してテストを手動で再構築しようとすると、期待される結果が得られるため、問題はユーザーモデル自体にあるようには見えません (user.valid? は、user.dup.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 > 

ユーザーモデルのコードは次のとおりです(これは問題ではないと思いますが?)

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

次のようにいくつかのプットをテストに追加して、テストが失敗した場所を特定しようとしました

  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

テスト スイートを実行したときの結果は次のとおりです。

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

上記から、@user.email オブジェクトが nil のように見えます! しかし、@user.dup が正しい値を正常に割り当てているため、これがすべてではありません...

テストが失敗する理由を説明できる人はいますか?

ありがとう、

4

1 に答える 1

1

before2 つのブロックとは対照的に、ここではブロックを使用する必要があると思いますit(最初のブロックにはテストが含まれておらず、2 番目のブロックには実行前に重複したユーザーが保存されていません)。

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
于 2013-10-20T01:06:13.223 に答える