9

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
4

4 回答 4

9

你想改变这个

config.after(:suite) do
  DatabaseCleaner.clean
end

对此:

config.after(:suite) do
  DatabaseCleaner.clean_with(:truncation)
end

否则,它将简单地回滚事务,这将留下事务开始之前存在的任何数据。

于 2013-12-04T21:26:51.097 回答
1

添加一个文件:

# 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

并取消注释

Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

spec/rails_heper.rb

于 2015-07-16T18:11:27.407 回答
0

这对我有用:

DatabaseCleaner.strategy = :truncation

...

before(:each) do
  DatabaseCleaner.clean
end
于 2013-11-30T03:21:04.343 回答
0

请显示规格。

您需要确保您的设置/拆卸是在之前/之后/其等语句中完成的。

如果您在上述范围之外进行了设置和变量分配,并且只是“在测试本身”,那么测试将在您遇到时爆炸。如果在设置中完成,则可以避免此问题。

你不应该像你一样试图用内部结构来调整。与 Ror 领域的许多事情一样,如果您这样做,您的代码可能会“偏离”轨道。Rails 旨在成为一个为您完成所有乏味工作的框架,您只需保持“在轨道上”。

于 2013-12-01T15:04:30.553 回答