RSpec leaves record in test database - ruby-on-rails

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?

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

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.

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

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.

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

Related

Fixtures for Apartment Gem

I'm trying to do some tests with my multi-tenancy rails app but getting into trouble with my fixtures. In my controller test I have the following setup:
setup do
Apartment::Tenant.create('test')
Apartment::Tenant.switch! 'test'
host! "test:3000"
sign_in users(:admin)
end
When running the test I get this Error:
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=255947101
I think the problem is that the fixtures are being created before switching to the test tenant. How do I create the fixtures after switching the tenant?
Ran into this same problem this morning ... I was able to get around it, at least for now, with this change in my test_helper.rb file:
# Customizing the base TestCase
module ActiveSupport
class TestCase
Apartment::Tenant.create('the-tenant')
Apartment::Tenant.switch! 'the-tenant'
fixtures :all
ActiveRecord::Migration.check_pending!
def setup
Capybara.app_host = 'http://www.my-somain.local'
DatabaseCleaner.strategy = :transaction
end
def teardown
Apartment::Tenant.drop('the-tenant')
Apartment::Tenant.reset
DatabaseCleaner.clean
end
end
end
Basically, I moved the tenant creation outside the setup method, where it previously resided. This seems to have fixed the issue with the fixtures being created outside the tenant on which I am testing.
I hope this helps ... not 100% sure it's ideal but it does have my tests running today :)

Resetting the database between rspec runs

I have a test like this, which fails after the first run
it 'should have a login count of 1' do
... (creates a user with 'test#example.com' as the email)
expect(user.login_count).to eq 1
end
The test fails because each time I run it, that user is still in the database and the login count keeps incrementing.
The login_count keeps incrementing because of a method in my program which either finds or creates the user, each time though, it increments the login_count by 1
What's the best way to have the test think the database is clear each time it runs?
In order to have a clean state in the database among each test execution you may want to use the database cleaner gem: https://github.com/DatabaseCleaner/database_cleaner
Rspec example setup (Extracted from github)
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end

Tell Rspec - don't delete my test_db when before running tests

I populate a database that I want to run rspec tests against.
Rspec seems to delete the db before it starts the tests. How can I tell Rspec not to delete this test_db?
I populate the db outside of Rails / Rspec environment. To build all the factories needed to build up the DB is just not practical for the scope of the project but I would like to test against existing DB.
You can manage clean your database using database cleaner gem, and The documentation recommends the following configuration for rspec as this link, but you change as the following:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
end
But, I prefer to create your database in test environment before scenario, as example:
describe "specific name for this scenario" do
before do
#object = create(:object) # using factory girl as example
end
end
so, this data'll be generate for each time you run your test-case, read more about creating data for rspec-test.
I used the advice given in this question: Rspec don't delete 2 specific tables
In spec_helper.rb:
Commented out call to truncate_all_tables.
Then changed line:
config.use_transactional_fixtures = true
to
config.use_transactional_fixtures = false

Does rspec access the database when tests are run?

I'm using rspec-rails to test a controller in my rails application. In one instance, I'm creating new objects to test that they're properly assigned to instance variables.
describe MainController do
describe "GET #index" do
it "properly assigns a colored ball" do
ball1 = Ball.create(color: 'red')
get :index
expect(assigns(:red_balls)).to eq([ball1])
end
end
end
When I run the test, does rspec access the database to create ball1 and then delete it once the test is run?
From the snippet in your question, Yes Rspec access the DB configured as test in the database.yml file, if you want to clean out the DB/Records created by Rspec you can use the database_cleaner gem you can configure it as you deem fit.
e.g:
add gem database_cleaner to your Gemfile
and the below to your spec_helper.rb file as specified by the database_cleaner documentation:
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
Then database_cleaner would truncate the tables in the test db and leave them in a pristine state
To add to what bjhaid said above - Rspec should only be accessing you 'test' database. Check out the config/database.yml to see the configuration of your different databases.
So you do not have to worry about things in your development or production databases interfering with your testing database.
Yes, RSpec allows your database calls to go through, but with the rspec-rails gem under the default configuration, it will execute each test within a database transaction and will roll back that transaction at the end of each example with no action required on your part. No additional gem is required. See https://relishapp.com/rspec/rspec-rails/docs/transactions.

rails test database won't wipe

I'm running rails 3.0.3 and using rspec-rails 2.4.1 with a postgresql database. Whenever I run my RSpec tests, the data remains at the end. Does anyone know how to get rails or rspec to wipe the test environment's data between each use?
Please tell me if there's any further information that could make answering my question easier.
Thanks!Tristan
Install the database_cleaner gem and then add this to your spec_helper.rb.
Spec::Runner.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
Use transactional examples to rollback the data after every test run
RSpec.configure do |config|
config.use_transactional_examples = true
end
You don't need any extra gem in order to clean your test DB between runs. In your spec_helper.rb file, configure rspec as follows:
RSpec.configure do |c|
c.around(:each) do |example|
ActiveRecord::Base.connection.transaction do
example.run
raise ActiveRecord::Rollback
end
end
end
Another possibility, that I just put myself through, is using the wrong before block.
I accidentally set a before block as an all instead of an each:
before :all do
user = FactoryGirl.create(:user)
sign_in user
end
This caused the user to stick around in the database for the entire rspec run, which caused validation collisions.
Instead, the before should be an each so that everything is kept clean through the rspec run:
before :each do
user = FactoryGirl.create(:user)
sign_in user
end
If you've made this mistake, then you will probably need to manually clean up your test database before things go back to normal. The simplest way to do that is probably to truncate each of the tables (aside from schema_migrations).

Resources