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


83

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

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

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

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

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具有用于测试的条目(对于并行测试gem来说很常见):

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

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

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

我认为可以通过Specjour::Configuration.prepare在.specjour / hooks.rb中进行设置来在每个specjour测试数据库上运行任意代码,因此,如果有任何我需要运行的rake任务或其他代码,则可以在其中运行。

Answers:


14

我在工作中设置CI系统时遇到了类似的问题,因此我逐步建立了一个系统来处理此问题。它可能不是最好的解决方案,但在我遇到的情况下它对我有用,并且我一直在寻找更好的做事方法。

我有一个需要设置的测试数据库,但也需要加载种子数据才能使测试正常工作。

解决rake任务的基本知识是使用--trace选项运行rake,以了解幕后情况。当我这样做时,我发现运行rake spec可以做很多事情,我可以在自定义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中进行加载。这样,我们可以节省测试数据库设置的几分钟时间。我在这里没有显示它,因为它使事情变得非常复杂-需要正确地生成它,而又不会过时。

高温超导


是的,我已经使用--trace运行rake spec并尝试在我的prepare specjour钩子中复制其某些任务,但尚未成功。我可能会编写一个完全独立的rake任务来进行设置,但这是我希望避免的另一步。
gerry3'5

169

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

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调用失败,因为无法删除数据库。棘手的事情。


47
一个更简单的解决方案是运行rake db:test:prepare
gerry3 2012年

7
rake db:test:prepare使用Postgres运行我没有问题。您可能由于其他原因看到了您的问题。
gerry3

如果db:test:prepare无法正常工作,则至少可以将命令内联以保存一些键入内容:RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load
funwhilelost 2014年

11
看起来就像rake db:test:prepare是Rails的4弃用
markquezada

8
您可以像这样链接耙任务:bundle exec rake db:drop db:create db:schema:load RAILS_ENV=test
davegson

14

提供的解决方案都需要加载Rails环境,这在大多数情况下由于非常大的开销和非常低的速度而并非理想的行为。DatabaseCleanergem也相当慢,它为您的应用程序增加了另一个依赖性。

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

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

最好的部分是:它将仅清除您已经有效接触过的那些表(未接触的模型将不会被加载,因此不会出现在中subclasses,这也是之前这不起作用的原因)测试)。而且,它在测试后执行,因此(希望)绿点将立即出现。

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

编辑

看到此答案已逐渐普及,我想对其进行编辑以确保完整性:如果您想清除所有内容表,甚至是未触及的表,您都应该能够执行以下“ hacks”之类的操作。

hack 1-预加载所有模型 subclasses方法

在致电之前进行评估subclasses

Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))

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

技巧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

整齐!这是非常有用的。
odigity 2013年


3

在经过改进的Rails 4应用程序中,bin/setup通常将my添加为包含

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

这与leviathan的答案非常相似,此外还为测试数据库添加了种子,例如

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

正如评论所提到的,如果我们要首先删除数据库,rake db:reset则只需这样做。

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


0

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

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

键入psql的命令提示符,然后运行下面创建一个测试数据库比你自己使用的帐户等。 CREATE DATABASE your_database_name OWNER your_db_owner;

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.