问题
This makes no sense to me, hope someone can help. I'm getting a single test failure when creating a user using a factory (seemingly similar tests pass).
In my user_spec.rb test file, the user was originally created like this. Using this initialization approach, all tests pass.
USER CREATION
user_spec.rb (without factory)
describe User do
before do
@user = User.new(name: "Example User", email: "user@example.com",
password: "foobar", password_confirmation: "foobar",
username: "username")
end
Most of the other tests for the app use factories. So, decided to replace the above with call to factory.
user_spec.rb (with factory)
describe User do
before do
@user = FactoryGirl.create(:user)
end
FACTORY
The factory looks like this.
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"
sequence(:username) { |n| "username_#{n}" }
TEST FAILURE
Here is the test failure when using the factory to create the user.
user_spec.rb
Failures:
1) User when email address is already taken
Failure/Error: it { should_not be_valid }
expected valid? to return false, got true
# ./spec/models/user_spec.rb:101:in `block (3 levels) in <top (required)>'
Finished in 12.61 seconds
178 examples, 1 failure, 2 pending
TEST
Here is the part of the test that fails when switching to the factory.
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
INSPECTION OF USER AND USER.DUP
My first thought was perhaps using the .dup on the factory created user was causing problems. Here is the @user and the @user.dup when output from their use in the test above (by adding the lines puts @user.inspect
and puts user_with_same_email.inspect
into the describe block. Both of these puts
are after the user_with_same_email.save
).
WITHOUT FACTORY (Test passes)
@user
#<User id: nil, name: "Example User", email: "user@example.com",
created_at: nil, updated_at: nil,
password_digest: "$2a$04$I/71i.fpTwfp4PqRwAvU4eUEjEkW/wubx6uVBqfNBShq...",
remember_token: nil, admin: false, username: "username">
user_with_same_email
#<User id: 1178, name: "Example User", email: "USER@EXAMPLE.COM",
created_at: "2012-04-24 06:01:07", updated_at: "2012-04-24 06:01:07",
password_digest: "$2a$04$I/71i.fpTwfp4PqRwAvU4eUEjEkW/wubx6uVBqfNBShq...",
remember_token: "rMS9jM0d4lobLc-A-pTTqA", admin: false, username: "username">
WITH FACTORY (Test fails)
@user
#<User id: 739, name: "Person 67", email: "person_67@example.com",
created_at: "2012-04-24 05:54:28", updated_at: "2012-04-24 05:54:28",
password_digest: "$2a$04$n4tToBVM2elz92cfHPKvte6dfHSBj4jDxG.w6DyKtGUR...",
remember_token: "fy2iifmhXVTFa1__d1dBJg", admin: false, username: "username_67">
user_with_same_email
#<User name: "Person 67", email: "PERSON_67@EXAMPLE.COM",
created_at: nil, updated_at: nil,
password_digest: "$2a$04$n4tToBVM2elz92cfHPKvte6dfHSBj4jDxG.w6DyKtGUR...",
remember_token: "fy2iifmhXVTFa1__d1dBJg", admin: false, username: "username_67">
What stands out above is that @user is not already saved without using the factory, whereas when using the factory @user is saved. I'm just not seeing how this effects the test in this case.
Any help would be appreciated. Thanks!
(The above code comes from Michael Hartl's Rails Tutorial, I'm working on some of the app feature extensions he mentions at the end of the tutorial.)
回答1:
The factory puts the record in the DB. User.new doesn't until it is saved. The original test doesn't check if user_with_same_email gets created, rather that 'it' (subject { @user }) can't be created because the email exists. After making your change to the @user, I had to rewrite the test:
describe "when email address is already taken" do
let (:user_with_same_email) { @user.dup }
specify { user_with_same_email.should_not be_valid }
end
回答2:
Thanks Eric. Building on your test ....
The original test was also testing for case sensitivity as well as uniqueness. This test passes and seems to do the trick. Any thoughts?
describe "when email address is already taken" do
let(:user_with_same_email) { @user.dup }
before do
user_with_same_email.email = @user.email.upcase
user_with_same_email.save
end
specify { user_with_same_email.should_not be_valid }
end
来源:https://stackoverflow.com/questions/10292640/rspec-test-failure-when-switching-from-initializing-attributes-to-factory