问题
I have added the database_cleaner gem to my rails application in order to clean my database between specs. Here's my current configuration for database_cleaner, located in spec/spec_helper.rb
:
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.start
DatabaseCleaner.clean
end
config.before(:each) do
DatabaseCleaner.clean
end
config.after(:each) do
DatabaseCleaner.clean
end
config.after(:suite) do
DatabaseCleaner.clean
end
Now, this configuration works fine, so long as every last spec that is run either passes or fails.
However, in the event of an error (rspec doesn't give you a nice little E
like minitest, it throws this sort of thing:
09:17:32 - INFO - Running: spec
/usr/local/rvm/rubies/ruby-1.9.3-p392/lib/ruby/gems/1.9.1/gems/activerecord-4.0.1/lib/active_record/validations.rb:57:in `save!': Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
), the database isn't cleaned! Residual data from the spec just before the error stays in the database. I suppose this is because database_cleaner doesn't regard the erroneous spec as finishing and so doesn't clean the database.
Now, this doesn't really cause any harm until you run your specs again. The residual data then causes an error analogous to this:
09:17:32 - INFO - Running: spec
/usr/local/rvm/rubies/ruby-1.9.3-p392/lib/ruby/gems/1.9.1/gems/activerecord-4.0.1/lib/active_record/validations.rb:57:in `save!': Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
Getting around this error is simple enough; running rails_env=test rake db:reset
or firing up your database shell and emptying the relevant tables with sql statements will clear this data and allow the specs to be run without a hitch.
However, this is getting annoying. One wrong character in any of my specs (anything to make it erroneous rather than a failure) causes my whole testing workflow to jam up, almost like the firing mechanism of an automatic weapon!
What are your suggestions regarding database_cleaner? Do you have any example configurations that allow for the database to be cleaned, even in the event of an erroneous test?
I'm using guard to run my rspecs that are further augmented with factory-girl:
Gemfile:
source 'https://rubygems.org'
group :development do
gem 'capistrano'
gem 'rb-fsevent'
gem 'debugger'
end
group :development, :test do
gem 'rspec-rails', '~> 2.14.0'
gem 'sqlite3'
gem 'guard-rspec'
gem 'guard-livereload', require: false
gem 'guard-shell'
gem 'webrick', '~> 1.3.1'
end
group :test do
gem 'factory_girl_rails'
gem 'capybara', '~> 2.2.0'
gem 'selenium-webdriver'
# capybara-webkit gem requires an application called 'libqtwebkit-dev' to build. To install 'libqtwebkit-dev' in Ubuntu, run
# sudo apt-get install libqtwebkit-dev
# gem 'capybara-webkit'
gem 'rb-readline'
gem 'launchy'
gem 'database_cleaner'
end
group :production do
gem 'pg'
# gem 'puma'
end
# rails version
gem 'rails', '4.0.1'
# standard library
gem 'sass-rails', '~> 4.0.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 1.2'
group :doc do
gem 'sdoc', require: false
end
# custom
gem 'activeadmin', github: 'gregbell/active_admin'
gem 'devise'
gem 'simple_form'
spec/spec_helper:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.include Capybara::DSL
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.start
DatabaseCleaner.clean
end
config.before(:each) do
DatabaseCleaner.clean
end
config.after(:each) do
DatabaseCleaner.clean
end
config.after(:suite) do
DatabaseCleaner.clean
end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# config.include RSpec::Rails::RequestExampleGroup, type: :feature
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
end
回答1:
You want to change this
config.after(:suite) do
DatabaseCleaner.clean
end
To this:
config.after(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
Otherwise, it will simply roll back the transaction, which will leave any data that existed before the transaction was started.
回答2:
This works for me:
DatabaseCleaner.strategy = :truncation
...
before(:each) do
DatabaseCleaner.clean
end
回答3:
Please show the spec(s).
You need to be sure that your setup/teardown is done in before/after/its, etc. statements.
If you have setup and variable assignment outside of the above and just 'in the test itself' then the test will bomb out as you are experiencing. If done in setup, this problem can be avoided.
You should not need to be trying to jigger with the internals the way you are. As with many thing in Ror land, if you're doing this, chances are you may be 'going' off the rails with your code. Rails is intended to be a framework that does all the tedium for you, you just have to stay 'on the rails'.
回答4:
add a file:
# RSpec
# spec/support/database_cleaner.rb
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
end
and uncomment
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
in spec/rails_heper.rb
来源:https://stackoverflow.com/questions/20295927/how-can-i-clean-my-database-between-erroneous-rspec-specs