如何在不运行rake规范的情况下为Rails rspec测试准备测试数据库?

时间:2011-05-06 19:29:01

标签: ruby-on-rails ruby-on-rails-3 rspec rspec2 specjour

经过重大故障排除后,我发现我需要运行rake spec一次(我可以使用control-c中止),然后才能直接运行rspec(例如,在我们规范的子集上)。我们正在运行Rails 3.0.7和RSpec 2.5.0。

显然,rake正在运行一些重要的数据库设置任务/代码(我们在根级别Rakefile和其他地方都有自定义代码)。

如何在不运行rake spec的情况下运行rake测试数据库设置任务/代码?

除了能够在文件子集上运行rspec之外,我还使用specjour在多个核心上传播我们的规范(尚未成功将它们传播到局域网中),但我看到了与直接运行rspec的行为相同:我需要在specjour工作之前在每个测试数据库上运行rake spec(假设有两个核心):

rake spec TEST_ENV_NUMBER=1
control-c (after tests start)
rake spec TEST_ENV_NUMBER=2
control-c (after tests start)
specjour

注意:我的config / database.yml有这个测试条目(对于并行测试宝石来说很常见):

test:
  adapter: postgresql
  encoding: unicode
  database: test<%=ENV['TEST_ENV_NUMBER']%>
  username: user
  password:

parallel_tests似乎正确设置了数据库,但我们的许多规范都失败了。

我还应该提一下,运行specjour prepare会导致Postgres记录无法找到数据库的错误,但会创建它们(没有表)。在后续运行中,不会记录任何错误,也不会创建任何表。我的整个问题可能只是prepare中的一个错误,所以我在github上报告了它。

我认为我可以通过在.specjour / hooks.rb中设置Specjour::Configuration.prepare在每个specjour测试数据库上运行任意代码,所以如果有任何rake任务或我需要运行的其他代码,它可能在那里工作

6 个答案:

答案 0 :(得分:144)

我建议删除测试数据库,然后重新创建并迁移:

bundle exec rake db:drop RAILS_ENV=test
bundle exec rake db:create RAILS_ENV=test
bundle exec rake db:schema:load RAILS_ENV=test

完成这些步骤后,您可以运行您的规范:

bundle exec rspec spec

gerry3注意到:

  

更简单的解决方案是运行rake db:test:prepare

但是,如果您正在使用PostgreSQL,那么因为rails环境被加载而无法工作,这会打开数据库连接。这会导致prepare调用失败,因为无法删除数据库。棘手的事情。

答案 1 :(得分:14)

所提供的解决方案都需要加载Rails环境,在大多数情况下,由于非常大的开销和非常低的速度,这不是所需的行为。 DatabaseCleaner gem也相当慢,它会为您的应用添加另一个依赖项。

由于上述原因,经过几个月的懊恼和烦恼,我终于找到了以下解决方案,正是我所需要的。它很好,简单,快速。在spec_helper.rb

config.after :all do
  ActiveRecord::Base.subclasses.each(&:delete_all)
end

关于这一点的最好的部分是:它只会清除那些你有效触及的表格(未加载的模型将不会被加载,因此不会出现在subclasses中,这也是为什么这不适用于之前测试)。此外,它在测试后执行,因此(希望)绿点将立即出现。

唯一的缺点是,如果在运行测试之前有一个脏数据库,它将不会被清除。但我怀疑这是一个主要问题,因为测试数据库通常不会受到外部测试的影响。

修改

看到这个答案已经获得了一些人气,我想编辑它的完整性:如果你想清除所有表,即使是没有触及的表,你应该能够做类似的事情。 “黑客”下面。

Hack 1 - 预加载subclasses方法

的所有模型

在致电subclasses

之前对此进行评估
Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))

请注意,此方法可能需要一些时间!

Hack 2 - 手动截断表

ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }

将为您提供所有表格名称,以及您可以执行以下操作的名称:

case ActiveRecord::Base.configurations[Rails.env]["adapter"]
when /^mysql/, /^postgresql/
  ActiveRecord::Base.connection.execute("TRUNCATE #{table_name}")
when /^sqlite/
  ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}")
  ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table_name}'")
end

答案 2 :(得分:13)

我在设置CI系统时遇到了类似的问题,所以我逐渐建立了一个系统来处理这个问题。它可能不是最好的解决方案,但它在我的情况下适合我,我总是在寻找更好的方法来做事。

我有一个我需要设置的测试数据库,但也需要为我们的测试加载种子数据。

对rake任务进行故障排除的基础是使用--trace选项运行rake以查看引擎盖下发生的情况。当我这样做时,我发现运行rake规范做了很多我可以在自定义rake任务中复制(或修改我认为合适)的东西。

以下是我们所做的一个例子。

desc "Setup test database - drops, loads schema, migrates and seeds the test db"
task :test_db_setup => [:pre_reqs] do
  Rails.env = ENV['RAILS_ENV'] = 'test'
  Rake::Task['db:drop'].invoke
  Rake::Task['db:create'].invoke
  result = capture_stdout { Rake::Task['db:schema:load'].invoke }
  File.open(File.join(ENV['CC_BUILD_ARTIFACTS'] || 'log', 'schema-load.log'), 'w') { |f| f.write(result) }
  Rake::Task['db:seed:load'].invoke
  ActiveRecord::Base.establish_connection
  Rake::Task['db:migrate'].invoke
end

这只是一个示例,并且特定于我们的情况,因此您需要弄清楚需要做什么才能获得测试数据库设置,但使用rake的--trace选项很容易确定

此外,如果您发现测试设置花费的时间太长(就像我们的情况那样),您也可以将数据库转储为.sql格式,并让测试数据库将其直接导入到mysql中进行加载。我们通过这种方式节省了几分钟的测试数据库设置。我没有在这里展示,因为它使事情变得非常复杂 - 它需要正确生成而不会变得陈旧等等。

HTH

答案 3 :(得分:5)

看来在Rails 4.1+中,最好的解决方案就是在ActiveRecord::Migration.maintain_test_schema!之后在rails_helper中添加require 'rspec/rails'

即。您不必再担心必须准备数据库了。

https://relishapp.com/rspec/rspec-rails/docs/upgrade#pending-migration-checks

答案 4 :(得分:3)

在一个有弹性的Rails 4应用程序中,我的bin/setup通常会被扩充为包含

puts "\n== Preparing test database =="
system "RAILS_ENV=test bin/rake db:setup"

这与leviathan's answer非常相似,加上测试数据库的种子,

  

rake db:setup #创建数据库,加载模式,并使用种子数据初始化
  (使用
db:reset 首先删除数据库)

正如评论所提到的,如果我们想先放弃数据库,rake db:reset就是这样做的。

我还发现,与rake db:test:prepare相比,这提供了更多反馈。

答案 5 :(得分:0)

我首先删除了测试数据库 rake db:drop RAILS_ENV=test

当尝试创建新的测试数据库时,我遇到了一个问题,因为我的用户帐户与拥有数据库的帐户不同,因此我在PostgreSQL中创建了数据库。

在命令提示符下键入psql,然后运行以下命令创建使用您自己的帐户以外的帐户的测试数据库。 CREATE DATABASE your_database_name OWNER your_db_owner;

然后在测试环境中运行迁移。 rake db:migrate RAILS_ENV=test