Testing the Controller with RSpec, Devise, Factory Girl
Asked Answered
F

2

5

I have models: Post and User(Devise). I am testing controller Post.

describe "If user sign_in" do

   before(:all){ 
     @user = Factory(:user)
   }

   it "should get new" do
     sign_in @user  
     get 'new'
     response.should be_success
     response.should render_template('posts/new')
   end

   it "should create post" do
     sign_in @user
     post 'create', :post => Factory(:post)
     response.should redirect_to(post_path(:post))
   end
 end  

But the second test fails:

Failure/Error: post 'create', :post => Factory(:post) ActiveRecord::RecordInvalid: Validation failed: Email has already been taken, Email has already been taken, Username has already been taken

How do I fix this?

Frieda answered 12/2, 2012 at 12:0 Comment(0)
I
7

You need a tool to clean your database between tests. Because you should be able to run each test with a clean database. I'm using database_cleaner, it's quite a famous gem and it works really well. It's easy to setup too. An example from the README ( RSpec related):

RSpec.configure do |config|

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end
Intonation answered 12/2, 2012 at 12:3 Comment(3)
When i include your code in spec_helper. I got an error Failure/Error: Unable to find matching line from backtrace ActiveRecord::StatementInvalid: SQLite3::SQLException: cannot start a transaction within a transaction: begin transactionFrieda
you don't need another gem for this.Station
I found the SQLite exception solution was to remove the clean_with(:truncation) and change the strategy entirely to DatabaseCleaner.strategy = :truncationBousquet
S
9

You don't need another gem for this. FactoryGirl has built in dynamic helpers for this. I suggest watching the short Railscast about this. Here is a snippet of how it works:

FactoryGirl.define do
  factory :user do
    sequence(:username) { |n| "foo#{n}" }
    password "foobar"
    email { "#{username}@example.com" }
Station answered 16/2, 2012 at 15:6 Comment(2)
If you are a rails developer and not using Railcasts, then you are doing it wrong.Station
but if you are a TRUE Rails developer, then you should link to free content first and then suggest the paid oneWelldone
I
7

You need a tool to clean your database between tests. Because you should be able to run each test with a clean database. I'm using database_cleaner, it's quite a famous gem and it works really well. It's easy to setup too. An example from the README ( RSpec related):

RSpec.configure do |config|

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end
Intonation answered 12/2, 2012 at 12:3 Comment(3)
When i include your code in spec_helper. I got an error Failure/Error: Unable to find matching line from backtrace ActiveRecord::StatementInvalid: SQLite3::SQLException: cannot start a transaction within a transaction: begin transactionFrieda
you don't need another gem for this.Station
I found the SQLite exception solution was to remove the clean_with(:truncation) and change the strategy entirely to DatabaseCleaner.strategy = :truncationBousquet

© 2022 - 2024 — McMap. All rights reserved.