Why is database_cleaner breaking my tests (minitest / capybara / factory girl)? - ruby-on-rails

I'm trying to get database_cleaner working with my test suite and I can't find anything online about this error:
ERROR Couldn't find User with id=1
The tests run fine until I add database_cleaner. This is how I'm using it in my test_helper.rb file:
# Database cleaner.
DatabaseCleaner.strategy = :truncation
class MiniTest::Spec
before :each do
DatabaseCleaner.clean
end
end
It also does not work if my strategy is :transaction.

According to the docs, the call to DatabaseCleaner.clean should be in an after hook, and DatabaseCleaner.start in a before hook (the start call may be unnecessary with the truncation strategy.
What may well be happening here is that database cleaner is clearing out any data you've setup in other before hooks before your actual test runs. It will depend which order the before hooks run in.

Related

How to clean database between different features in cucumber rails?

I am having trouble in cleaning database between features.
I tried using Before hooks but it runs for each scenario but I only need to clean database at the start of each feature and not between scenarios.
Any suggestions would be helpful.
I use DatabaseCleaner https://github.com/DatabaseCleaner/database_cleaner I'm satisfed
config.before(:each) do |spec|
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.start
...
end
config.append_after(:each) do
DatabaseCleaner.clean
end
in rails_herper.rb
Here is sample config
before(:all) do
DatabaseCleaner.clean
end
In RSpec, you have tags, types, hooks etc..
In your case easiest way will be adding before(: all) in each file.
This will start cleaning before all tests in described context.
From documentation Rspec Docs
before(:all) blocks are run once before all of the examples in a group
The database should be cleaned before every scenario as Cucumber intends. Stopping Cucumber from doing this is a false optimisation, and a common anti-pattern followed by lots of less experienced Cucumber users. Scenarios should never be dependent on each other.
To get this to work remove any code you have added to your application to restrict how cucumber cleans the database.
If you are not sure how to do this create a new rails project using the same ruby and rails versions you are using and then add the cucumber-rails gem. It will setup everything as intended. You can use the diff of before/after cucumber-rails to compare.
You can clean database before (not after) each scenario with the following code. Just add it to your features/support/env.rb
Cucumber::Rails::Database.autorun_database_cleaner = false
DatabaseCleaner.strategy = :truncation
Cucumber::Rails::Database.javascript_strategy = :truncation
Before do
DatabaseCleaner.clean
end
Just a work around/hack, just in case you haven't found a solution yet.
The trick here is to use tagged cucumber hooks!
Provide a tag like #LastScenario in your last scenario in the feature file/s.
Then using the #After hook of cucumber perform the action, say data clean up in your case.
Something like:
#LastScenario
Scenario: My Scenario Name
Given I have something...
And then in the Hooks.java Class:
public class Hooks {
#After("#LastScenario")
public void dataCleanUp() {
CleanUpScripts cleanUpScripts = new CleanUpScripts();
cleanUpScripts.dataCleanUp();
}
}
Same can be done using #Before Hook as well - based on what is required.

Rails 5 - Unable to Cleanse Test DB

I've recently started testing my app using RSpec. Being the testing noob that i am, i did not install the full suite of tools that people normally use (namely FactoryGirl, also now known as FactoryBot. And DatabaseCleaner).
Anyway here's what happened. After getting my feet wet with RSpec, i started using FactoryBot so that my tests looks less convoluted. Note that :user is a Devise object.
# spec/models/first_test_spec.rb
FactoryBot.create(:user)
#Other Code
So i'm doing stuff with my first_test_spec.rb and i run it and everything is working perfectly fine. I then create my 2nd spec file
# spec/models/second_test_spec.rb
FactoryBot.create(:user)
#Other Code
Now here comes the problem. My tests are failing because FactoryBot.create(:user) is invalid, due to Devise requiring unique emails. Clearly this indicates that the data from my first_test_spec is persisting hence the error.
So i attempt to install DatabaseCleaner and hopefully clear my Test DB after each run. My rails_helper looks like this:
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'support/factory_bot'
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
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
end
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end
I think i've got everything set up correctly, so i'm uncertain if the errors are still occurring due to my DatabaseCleaner being set up wrongly.
Anyway, running rspec still throws the same error, where second_test_spec cannot create the user object because the email already exists (a validation that comes with Devise itself).
I then proceed to run the following:
rake db:test:prepare
rspec spec/models/second_test_spec.rb
And it still throws the same error. So right now, i have no idea if my database is being cleanse after running rspec. But i'm quite certain that i have been unable to purge my test database.
So i guess i really have 2 questions/problems:
1) How do you purge your test database? (Googling reveals that rake db:test:prepare is the way)
2) Is my DatabaseCleaner setup correctly? If so, shouldn't it be purging the database?
UPDATE:
As suggested to me in the comments, using sequence for creating unique fields with FactoryBot is recommended. Obviously that made the problem go away because there would no longer be validation errors from Devise.
I then went on to test a couple of things.
rails c test
I ran this to check my test database and it was indeed empty. This indicates that DatabaseCleaner is working perfectly fine. What i fail to understand then, is why the need to sequence my email creation in FactoryBot? Or i suppose, i fail to understand how does RSpec "compile & run".
puts #user.email
So i wanted to print out the emails to look at the sequencing to see if i'm able to decipher the problem. Here's what happens:
running rspec spec/models/first_test_spec.rb
Tutor email yields the number 2.
running rspec spec/models/second_test_spec.rb
Tutor email yields the number 3.
running rspec
Tutor email yields the numbers 2 & 5.
So i'm not sure if there are "problems" with my test suite. Clearly my original problem has been fixed, and this is a separate topic altogether. But i figured if anyone would like to explain this mystery to anyone else who chances upon this thread may wish to do so.
Seeing your full spec files would help. If you are running the specs as you've written - creating a user outside of an example group or a before block - that will cause records to be written outside of the cleaning strategy scope and can cause data to remain across examples. Your DBcleaner config looks to be set up fine otherwise.
rake db:test:prepare is the correct way to clean out your test db but shouldn't need to be ran often unless you have migration changes. You can jump into a rails console within the test environment rails c test and look around to see if there are any records left behind.
As a side note you can flip config.use_transactional_fixtures from false to true and remove DBcleaner altogether from your app. Just make sure there is no residual data in your database before going this route.

Rspec tests failing if run all together

I've 2 _spec files: the first containing unit test, the other one some integration tests.
While running them by specifying file name they are alle green, while running them as "rspec" 3 of them are failing.
I'm using database_cleaner gem to clean test db around each test.
config.use_transactional_fixtures = false
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
I'm using "let" to instantiate objects and FactoryGirl to create sample objects.
Has anyone experienced something like this before?
Some issues could be:
Class variables that you are modifying and not resetting between tests. Class variables are anti-patterns and should generally be avoided.
You aren't properly stubbing things like constants.
Anything that maintains a state between tests can cause the issue you are seeing. Use your debugger to check the state of objects during each test.
I've solved my problem by moving from def to let. Be aware of defines

What happens that slow down my specs?

I am using Ruby on Rails 3.2.2, FactoryGirl 3.1.0, FactoryGirlRails 3.1.0, Rspec 2.9.0 and RspecRails 2.9.0. In my spec files (about 1300 Examples each file), before each Example runs, I seed the database and create and store few records using factories:
# spec/spec_helper.rb
config.before(:suite) do
# Cleans the database.
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
# Seeds the database.
load "#{Rails.root}/db/seeds.rb"
end
I would like to know why, when I run the rspec ./spec/models/my_model_spec.rb command in the Terminal window, my specs start to run quickly but after a bit (that is, after it has run about 300 Examples) those go slowly. My examples are very simple and almost the same in terms of performance:
it "can not update title" do
#article.update_attribute(:title, "Sample title").should be_false
end
After a certain number of tests, Examples like that above take 20/30 seconds to complete (!) and sometime also 60/120 seconds (!!!).
What happens after run about 300 Examples that slow down my specs also if those Examples are very simple and almost the same in terms of performance? Is there a reason to that behavior?
Note I: I tried to run specs in isolation and those are all fast.
Note II: When I run specs a ruby process in my "Activity Monitor" (I am using a Mac OS X running Snow Leopard 10.6.8) go to use 100% of CPU quickly.
Try cleaning your database after every example. Put this in your rspec_helper configure block:
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end

individual spec passes when run alone, but fails when all specs are run

I have 30 specs in my foo_controller_spec.rb and when I run the entire file using spec, I get 4 failures and 2 pending. When I run the 4 failing specs individually, 3 of them still fail, but one of them passes. At first I thought it was a database issue, that the data wasn't being cleaned out properly between runs. So I installed database_cleaner (http://github.com/bmabey/database_cleaner) and added this code to my spec_helper:
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
Sham.reset
login
end
config.after(:each) do
DatabaseCleaner.clean
end
Now when I run my specs I can see that the tables are truncated between each spec so I know it's working, but the spec still fails when run with all the other specs but passes when run alone. What am I missing here?
I had exactly the same issue and was going out of my mind!
I tracked the issue like this (with Textmate):
select your files in project drawer (multiple files) and then go to "Bundles > Rspec > Run examples in selected files/directories".
The trick is to find which file is causing interference with others.
For me it was changing of I18n.locale in one file which caused the locale to be changed for all other examples!
I lost a few hours going nuts with this...
Just in case it helps others: I had a similar problem and found out I had
stray Rspec.configures that were overriding for all tests down the line
WebMocks enabled in one test that seem to cascade to following on tests until i I included in the spec_helper so connections were on by default
RSpec.configure do |config|
config.before(:suite) do
WebMock.allow_net_connect!
I Had a similar issue today that took quite a bit of time to resolve.
This fails:
module SomeModule
describe SomeController do
it 'does something'
end
end
This passes:
describe SomeModule::SomeController do
it 'does something'
end
The issue has to deal with scoping.
The command rspec --bisect, or --order rand:21237 --bisect if you see an error regarding ordering, is a good first step towards debugging. Add --bisect=verbose for more information.
Link to RSpec GH issue

Resources