我的@user模型有一套测试(遵循mhartl&#39教程),但莫名其妙地我对电子邮件唯一性的测试已经开始神秘失败
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后返回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成功分配了正确的值......
有人可以解释为什么测试失败了吗?
谢谢,
答案 0 :(得分:1)
我认为你需要在这里使用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