DMiller
DMiller

Reputation: 263

RSpec leaves record in test database

Whenever I run a user test, RSpec leaves the Fabricated user in the test database after the test has completed, which is messing up my other tests. I will do a rake db:test:prepare, but when I run my tests again, the record is recreated in my database. I have no idea why this is happening. It only happens with user objects.

In my spec_helper file I even have:

config.use_transactional_fixtures = true

Here is an example test that creates a record:

it "creates a password reset token for the user" do
  alice = Fabricate(:user) 
  post :create, email: alice.email
  expect(assigns(alice.password_reset_token)).to_not eq(nil)
end

Fabricator:

Fabricator(:user) do
  email { Faker::Internet.email }
  password 'password'
  name { Faker::Name.name }
end

Could this have anything to do with my users model?

Upvotes: 15

Views: 14976

Answers (5)

Samuel Cortez
Samuel Cortez

Reputation: 55

My problem turned out to be that I was was using before(:all) in my RSpec files which I found out the hard way that the data created does not get rolled back. I switched to before(:example) per this article: https://relishapp.com/rspec/rspec-rails/docs/transactions

Upvotes: 0

Brock90
Brock90

Reputation: 814

you should use a gem called database_cleaner that will truncate your database and reset everything automatically so in your gem file add the gem database_cleaner after that inside your spec_helper.rb configure it

spec_helper.rb

config.use_transactional_fixtures = false

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

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

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

and then create a new file in your spec/support directory

spec/support/shared_db_connection.rb

class ActiveRecord::Base
  mattr_accessor :shared_connection
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end
end
ActiveRecord::Base.shared_connection=ActiveRecord::Base.connection

Now whenever you run your tests the database will be reset.This was taken from the book 'Everyday Rails testing with RSpec' by Aaron Sumner

Upvotes: 26

Yossi Shasho
Yossi Shasho

Reputation: 3640

The simplest solution is to make sure RSpec tests run in transactions (Rails does this by default)

spec_helper.rb

config.around(:each) do |example|
  ActiveRecord::Base.transaction do
    example.run
    raise ActiveRecord::Rollback
  end
end

Upvotes: 1

iain
iain

Reputation: 16274

Each test is wrapped in a database transaction. That means that everything created during the test should be gone when the test finishes. Therefore, I would suspect that whatever you have in your database was made outside the test itself (like in a before(:all) block).

Also this doesn't guarantee that your database will be empty each time you run your tests. It might be possible that you accidentally added a record somehow, and now it just keeps reverting to that state.

If you want to make sure your tests have a shiny database each time, you should have a look at the database_cleaner gem.

Upvotes: 10

Tyler
Tyler

Reputation: 11509

If I had to guess, the line post :create, email: alice.email seems like a likely candidate for doing the actual user creation.

Stub that line out with an bogus test and see if you're still getting a user created in the DB.

Upvotes: 0

Related Questions