0

I'm doing exactly what is says in the documentation, but still getting a validation error:

Validation failed: Email has already been taken

FactoryGirl.define do
  sequence :email do |n|
    "test#{n}@factory.com"
  end

  factory :user do
    email           
    password              '12345678'
    password_confirmation '12345678'
    goal_id               1
    experience_level_id   1
    gender                'Female'
  end
end

Anyone know what I'm doing wrong here?

EDIT:

Here is the failing spec. It works fine if you uncomment subject block and comment out the FactoryGirl stuff. I'm trying to switch to using FactoryGirl.

require 'spec_helper'
require 'cancan/matchers'

describe User do
  # subject(:user) do
  #   Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
  #   User.create!(email: 'test@test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
  # end
  FactoryGirl.create(:program)
  puts FactoryGirl.create(:user).inspect

  it "should be assigned a program when it's created" do
    user.programs.should exist
  end

  it "should be valid with a name, goal, password, password_confirmation, experience_level, and gender" do
    user.should be_valid
  end

  it { should respond_to(:programs) }
  its('programs.last.name') {should == 'Test'}

  it "should be assigned imperial as the default measurement_units" do
    user.measurement_units.should eq("imperial") 
  end

  it 'validates presence of gender, goal_id, and experience_level_id' do
    user = User.new(gender: nil)
    user.should validate_presence_of(:gender)
    user.should validate_presence_of(:goal_id)
    user.should validate_presence_of(:experience_level_id)
  end
end

Edit 2:

I've updated my spec following the suggestion of one of the answers, so now my spec runs, but I get a failing test with a validation error. Here is the updated code:

describe User do
  subject(:user) do
  #   Program.create!(name: 'test', gender: 'Female', goal_id: '1', experience_id: '1')
  #   User.create!(email: 'test@test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female')
    FactoryGirl.create(:program)
    FactoryGirl.create(:user)
  end

  it "should be assigned a program when it's created" do
    user.programs.should exist
  end

And the message from the failing test:

Failures:

  1) User should be assigned a program when it's created
     Failure/Error: FactoryGirl.create(:user)
     ActiveRecord::RecordInvalid:
       Validation failed: Email has already been taken
     # ./spec/models/user_spec.rb:9:in `block (2 levels) in <top (required)>'
     # ./spec/models/user_spec.rb:13:in `block (2 levels) in <top (required)>'

Any ideas?

Arel
  • 3,888
  • 6
  • 37
  • 91
  • Your sequence setup looks OK. You can validate that by including `puts FactoryGirl.create(:user).inspect` in your spec. Is your users table accidentally persisting between rspec runs in the test database? Is there somewhere that you are using `dup` to copy an existing user and then trying to call `save!` instead of `save`? – cschroed Oct 08 '13 at 00:38
  • This has been really confusing me. My user table is persisting between rspec runs in the test db, but only when I use FactoryGirl. When I create a user simply by doing `subject(:user) do; User.create!(email: 'test@test.com', password: '12345678', password_confirmation: '12345678', goal_id: '1', experience_level_id: '1', gender: 'Female'); end` it works fine, and I don't get a validation error if I run the test twice. – Arel Oct 08 '13 at 00:58
  • Would you share your failing spec? – Peter Alfvin Oct 08 '13 at 01:04

2 Answers2

2

You can't just create Factory instances in the middle of a test class like that. FactoryGirl is a replacement for the instantiation you had in the code before - leave the subject block, and simply replace the two create lines with the FactoryGirl calls.

(even better, they should be let blocks not a subject block, but that's a different story)

If you are not doing things in a context Rspec knows about, it has no way of cleaning up afterwards.

sevenseacat
  • 24,699
  • 6
  • 63
  • 88
  • 1
    @Arel This is what I suspected. See also http://stackoverflow.com/questions/3497135/why-isnt-factory-girl-operating-transactionally-for-me-rows-remain-in-databa – Peter Alfvin Oct 08 '13 at 01:39
  • Thank you! I'm trying to write better tests, and there is a lot of stuff to figure out. Do you have a link to the documentation on using let blocks instead of subject blocks? Do I use let the same way I would use subject? – Arel Oct 08 '13 at 01:45
  • Nevermind, I was able to pass all but one test, and the failing test shows the same validation error. I'm getting much further along though. – Arel Oct 08 '13 at 01:50
  • Just updated my question with the updated information. Thanks for the help! – Arel Oct 08 '13 at 01:53
  • So I reset the test database, and the validation error went away. – Arel Oct 08 '13 at 03:18
0

What do you have in your Gemfile? I have better success using this

  gem 'factory_girl_rails', :group => :test

and not listing it in the "group :development, :test do" section.

mobileAgent
  • 1,621
  • 1
  • 12
  • 7