← Back to Upcase

Strange DatabaseCleaner results


(Jon Seidel) #1

In the test suite for my app, I use DatabaseCleaner to clear things out for each test. I’ve got a strange situation where one test fails roughly every other time I run the test suite, although that test passes when run individually. I’ve seen this occasionally with other tests in the suite.

Here’s the failure:

  1) FactoryGirl creates a valid user record
     Failure/Error: user = FactoryGirl.create :user, :login => 'joe', :password => 'password', :email => 'joe@example.com'  
     ActiveRecord::RecordInvalid:   
       Validation failed: Email has already been taken, Email has already been taken, Login has already been taken  
     # ./spec/factories/factories_spec.rb:5:in `block (2 levels) in <top (required)>'    

Here’s the test currently failing; I don’t think the problem is with this particular test.

require 'spec_helper'

describe FactoryGirl do
  it "creates a valid user record" do
    user = FactoryGirl.create :user, :login => 'joe', :password => 'password', :email => 'joe@example.com'
    expect(user.login).to eq 'joe'
  end 
end

Here’s my DatabaseCleaner setup, stored in ./spec/support/database_cleaner.rb. I’ve turned off several options trying to stabilize my tests:

require 'database_cleaner'

RSpec.configure do |config|

  # From Avdi Grimm: http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/

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

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

  #config.before(:each, :js => true) do
  #  DatabaseCleaner.strategy = :truncation
  #end

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

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

end

I also have config.use_transactional_fixtures = false in my spec_helper.rb file.

Any ideas as to what I’m doing wrong here?


(Charlieanna) #2

Give this a try

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

     config.before(:each) do |group|
       case group.example.metadata[:type]
       
       when :request
         DatabaseCleaner.strategy = :truncation
       else
         DatabaseCleaner.strategy = :transaction
       end
       DatabaseCleaner.start
     end

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

(Jon Seidel) #3

Thanks, @charlieanna, but it gave even stranger results :=) I ran rspec spec repeatedly and got the following results in terms of number of errors reported:

14, 1, 11, 3, 7, 13, 0, 0, 0, 7, Segmentation fault , 14, 8

Really wierd; it looks like each test sometimes is put into an ‘unclean’ state which triggers a failure somewhere down the line in the next rspec run.


(Charlieanna) #4

Did you restart your spork or guard server?

I think you are failing your validations by using the factorygirl.


(Jon Seidel) #5

Not using guard / spork. I removed that FactoryGirl spec and now all my specs run reliably… quite frankly, I have no idea why that worked… but thank you! Maybe you or someone else can explain the internal machinations going on here.


(Charlieanna) #6

I just figured something today abt using FactoryGirl along with the database_cleaner and the integration tests. I am not sure what you are doing but still I would like to explain what I learned.

First, when you run things using the integration tests, your browser is evoked which makes the browser start a new thread on which the a new connection is established to the database. So if you were using FactoryGirl along with it then FactoryGirl and your browser both would be trying to access the database at the same time which makes your database to get locked. To avoid this you use truncation strategy. What that does is that after each test it deletes the whole database and creates one new again, so this happens for each test and thus avoiding the database from getting locked because the tests are somehow getting cleaned after each tests. Or is simpler words

 truncation removes all data from the database and transaction rollbacks all changes that has been made by the running scenario.

Or in transaction whatever records were created when a test ran are simply deleted whereas in truncation all the data are deleted and tables are created again.

Because of this you can use FactoryGirl.create along with integration tests by using transactional strategy. You have to use truncation. You can transaction with models and controller specs.

I am not sure how your factories.rb look like but I think you are failing validations there.

Maybe if you could show your file here I might be able to help.