Does rspec access the database when tests are run? - ruby-on-rails

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.

Related

Clean out, or reset test-database with Rspec and Mongoid 5.0 on Rails 4

When I run my rspec tests, many fail due to stale data in my mongodb database. AFAIK it is far better to test with a clean database.
How can I clean and/or re-seed the database before each test?
You can use database_cleaner gem to accomplish this task.
From their documentation:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do |example|
DatabaseCleaner.strategy= :truncation
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
As you are using Mongoid ORM, you may also need to specify it explicitly:
# How to setup your ORM explicitly
DatabaseCleaner[:mongoid].strategy = :truncation
Update:
I see an open issue for MongoID 5
To make it work, you can monkey patch the Mongo Ruby driver class as mentioned in the issue.
module Mongo
class Collection
class View
def remove_all
remove(0)
end
end
end
end
Athough it's not a great solution!
The fix to the problem is there in the master branch of database_cleaner(1.4.1) gem. Install the gem from master to fix the problem (until there is the version bump). Expected to get fixed in next version.
gem 'database_cleaner', :git => 'https://github.com/DatabaseCleaner/database_cleaner.git'

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

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?
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

Rspec Integration Test not Cleaning the Database

The database is not being cleaned after each integration test. The value stays in the database.
Is there an option I should have to make this happen?
Thanks
I think https://github.com/bmabey/database_cleaner is what you need.
For anyone using before(:all) hooks, be aware that these hooks are executed before the transaction associated to the fixture is opened. This means that any data created by before(:all) hooks will not be rolled back by transactional fixtures. You can read more in the RSpec documentation.
I just wanted to mention this because I was bit by it and my initial instinct was to jump to Database Cleaner (which wound up not being needed and eventually not working).
How do I prepare test database(s) for Rails rspec tests without running rake spec?
My answer there might be of interest to you. it's a nice solution. For your case, you would probably need something like
config.after :each do
ActiveRecord::Base.subclasses.each(&:delete_all)
end
Look here for a tutorial: http://railscasts.com/episodes/257-request-specs-and-capybara
It describes Database Cleaner besides Rspec and Capybara
You want DatabaseCleaner, but you may find that the :truncation strategy is a bit too slow to run all the time. It's really only necessary for integration tests, so you can do this:
# spec/spec_helper.rb
require 'database_cleaner'
config.before(:suite) do
DatabaseCleaner.clean_with :truncation
DatabaseCleaner.strategy = :transaction
end
config.before(:each) do |group|
# The strategy needs to be set before we call DatabaseCleaner.start
case group.example.metadata[:type]
when :feature
DatabaseCleaner.strategy = :truncation
else
DatabaseCleaner.strategy = :transaction
end
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
# spec/features/your_feature_spec.rb
require 'spec_helper'
describe "An integration test", :type => :feature do
end
# spec/model/your_model_spec.rb
require 'spec_helper'
describe "A unit test" do
end
Obviously, this only applies if you're doing integration tests with RSpec directly vs. doing them with Cucumber.
There are two ways to accomplish this:
Configure transactional examples for each individual test.
Configure transactional examples for all the tests.
If you opt for option 1: At the top of the spec file, after:
require 'spec_helper'
Add:
RSpec.configure {|c| c.use_transactional_examples = true }
That will roll back the transactions after each example.
2.If you want to configure it globally, then, in the spec_helper.rb
RSpec.configure do |config|
...
config.use_transactional_examples = true # Add this
...
end

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