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
Related
I'm new in rails. In my project i use rspec + capybara + poltergeist + selenium + database_cleaner.
Source code github link
I have postgresql 9.5.5, ubuntu 16.04 LTS.
When run test
rspec spec/controllers # everything work fine
When run
rspec spec/features # everything work fine too
But when i run all tests
rspec # part of tests fail
When run first acceptance test with :selenium -> question_id in browser 28, but must be 1, because it use database_cleaner.
Why database_cleaner not clean my database? What i do wrong? I spent a day to find a solution, but not found nothing.
Help me please.
P.S. It's a training project.
My Database_Cleaner configuration is:
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
Warden.test_reset!
if Rails.env.test?
FileUtils.rm_rf(Dir["#{Rails.root}/public/uploads"])
end
end
Cleaning the tables means it deletes all records, it doesn't necessarily mean it resets the index counters - just like if you delete record 3 and then add a new record - the new one would be 4. So in your case it's possible 27 records have been deleted and the next one you create would be 28 even though there's only 1 actual record. Query the database to see how many actual records are there to verify that.
Next, your database cleaner config should be more like the recommended config - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example . append_after vs after is important for stability and checking the driver name vs just the :js metadata is too.
When checking for the href '/uploads/attachment/file/1/test_file.dat' in your tests you shouldn't be checking for a hardcoded '1' there you should check based on the record id number of the record you created. So "/uploads/attachment/file/#{question.id}/test_file.dat" (obviously question.id will depend on what objects you've created and your variable names, but that matches at least one of your tests I think.
Additionally after a quick look at your specs - anywhere you're doing expect(current_path).to eq ... is wrong. You should be doing expect(page).to have_current_path(...). The first way disables the retrying behavior of Capybara and will lead to flaky tests.
And finally - where you have expect(page).not_to have_content t('common.button.ready'), I'm guessing that should be expect(page).not_to have_button t('common.button.ready')
Here you could read how to config a database_cleaner with RSpec and Capybara - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example
I'm trying to clean up a projects specs, however I'm running into an odd issue. I have a simple sign up test(using devise). What's going on is anything created in the db is not persisting across the entire spec. So If I create a user in the spec file that user will not show up in the controller and vice versa. Devise is creating the User and saving it. I first I thought maybe they were hitting different db's or using transactions. did this simple output from each spec file and spec'd code(the controller).
puts Rails.configuration.database_configuration[Rails.env]
puts ActiveRecord::Base.connection.open_transactions
but both are coming back with the same thing.
{"adapter"=>"postgresql", "pool"=>5, "timeout"=>15000, "port"=>5432, "host"=>"localhost", "database"=>"db_name_test"}
0
DatabaseCleaner is being used to clean the db, that's basically following the standard setup.
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, type: :feature) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
update
checked threads, there are a total of 8, only one running at a time, but the object hash is different. Does that matter?
- spec file -
#<Thread:0x007f208444e660>
- specd code -
#<Thread:0x007f2088a075d0>
any config options I should check or thoughts?
I have a few tests in my suite that absolutely need an empty database to run.
Thing is, rails is automatically loading the fixtures for every test, and I can't seem to find a way to have it not load for this specific test.
I could drop the database before each test, but that's slow and requires all other tests that require fixtures to reload the fixtures afterwards.
Is there any way to have a certain test class (i.e. "NoFixturesTest") not load the fixtures (or unload them), without breaking all other tests?
Thanks!
EDIT:
Thanks to the answer below, I made this:
module DisableFixturesHelper
def self.included(base)
base.setup :setup_drop_db
# Have a unit test double-check that the fixtures are really gone
base.test "0 fixtures not loaded" do
assert_equal 0, Table1.count, "Table1 isn't empty!"
#etc
end
end
# Call to reset the db and therefore disable fixtures during a single unit test
def setup_drop_db
Rails.logger.info { "Dropping database." }
DatabaseCleaner.clean_with :truncation
end
end
And then in the TestCases that require an empty database (no fixtures), I add
include DisableFixturesHelper
The problem with this is that this drops the database once per test, AFTER the fixtures have already been loaded, so it's really slow. It's literally reloading the fixtures before the start of each unit test, just to drop them.
Still, it works.
do you know DatabaseCleaner ???
maybe it can help, you can also define what don't delete
something like:
DatabaseCleaner.strategy = :truncation, {:except => %w[widgets]}
here is an initializer that I always use:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
end
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
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).