在`rake test`之后执行一个rake任务

4

我正在尝试创建一个rake任务,用于Rails 4.0.2(Ruby 2.2.3)项目中创建测试数据库,插入种子数据,然后运行测试套件,最后通过删除测试数据库来清理工作。以下是一个简单的示例:

task better_test: :environment do
  Rake::Task["test:setup"].execute
  Rake::Task["test"].execute
  Rake::Task["test:cleanup"].execute
end

上述任务确实调用了test:setup rake任务(创建/填充测试数据库),然后调用test rake任务,并最终调用test:cleanup rake任务。然而,问题在于上一次的test:cleanup被调用时,test rake任务还没有完成运行。是否有办法在之前任务完成后调用清理rake任务呢?
以下是使用trace运行任务的输出:
$ RAILS_ENV=test be rake better_test --trace
/usr/local/rvm/gems/ruby-2.2.3/gems/activesupport-4.0.2/lib/active_support/values/time_zone.rb:282: warning: circular argument reference - now
/usr/local/rvm/gems/ruby-2.2.3/gems/honeybadger-1.16.3/lib/honeybadger/rack/user_feedback.rb:51: warning: circular argument reference - action
** Invoke better_test (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute better_test
** Execute test:setup
Creating test database.
** Execute db:test:setup
** Execute db:test:create
** Execute db:create
** Execute db:test:load
** Execute db:schema:load
** Execute db:test_project:setup
** Execute db:test_project:create
** Invoke db:create (first_time)
** Invoke environment
** Execute db:create
** Execute db:test_project:migrate:down
** Execute db:test_project:migrate:up
** Execute db:test_project:seed
** Execute test
** Invoke test:run (first_time)
** Invoke test:units (first_time)
** Invoke test:prepare (first_time)
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment
** Invoke db:migrate:load (first_time)
** Invoke environment
** Execute db:migrate:load
** Execute db:abort_if_pending_migrations
** Execute db:test:prepare
** Execute db:drop
** Execute db:create
** Execute db:load
** Invoke db:schema:load (first_time)
** Invoke environment
** Execute db:schema:load
** Execute test:prepare
** Execute test:units
** Invoke test:functionals (first_time)
** Invoke test:prepare
** Execute test:functionals
** Invoke test:integration (first_time)
** Invoke test:prepare
** Execute test:integration
** Execute test:run
** Invoke test:decorators (first_time)
** Invoke test:prepare
** Execute test:decorators
** Execute test:cleanup
** Execute db:test:drop
** Execute db:drop
** Execute db:test_project:drop
** Invoke db:drop (first_time)
** Invoke environment
** Execute db:drop
Run options: --seed 19360

# Running tests:

EE....

Finished tests in 0.037493s, 160.0278 tests/s, 106.6852 assertions/s.

从结果可以看出,任务是按顺序调用的,但清理任务在测试完成之前就执行了。有什么想法来解决这个问题吗?

3个回答

4
事实证明,这与 rake 的关系较小,更多地与 Minitest 执行其测试的方式有关。我在问题中提到,看起来 rake 任务是按正确顺序调用的,但出于某种原因测试稍后执行。原因是 Minitest 利用 ruby 内核方法 at_exit 来执行测试。测试文件在调用 rake test 时读取,但所有测试都是在 ruby 程序结束后执行的,甚至在我的后续 rake 任务之后执行。以下是一篇博客文章,详细解释了这个问题: http://blog.arkency.com/2013/06/are-we-abusing-at-exit/.

你有解决办法吗? - neeraj

2

尝试使用rake标准语法调用多个任务:

task better_test: ["test:setup", "test", "test:cleanup"]

也许这可以解决你的问题。
此外,似乎Rake在执行任务之前实际上会构建应运行所有任务的列表,并且只运行每个任务一次。例如:
task :a
task :b
task :c

task better_test: ["a", "b", "c", "b"]

导致的结果是:

$ rake better_test -t
** Invoke better_test (first_time)
** Invoke a (first_time)
** Execute a
** Invoke b (first_time)
** Execute b
** Invoke c (first_time)
** Execute c
** Execute better_test

正如您所看到的,任务b只运行一次(第一次)。我相信你的test:setuptest在某种程度上依赖于test:cleanup任务。因此它比预期提前调用。


Dmitry,这是一个好想法,但结果相同。我真的觉得这与 rake 无关,而更多地与 minitest 如何执行测试有关。 - Tyler Amos
我在答案中添加了一些其他的想法,可能你的 test:setuptest 已经调用了清理函数(不确定为什么,但可能是你或某个 gem 添加了依赖项以运行 cleanup),所以它根本不会第二次被调用。 - Dmitry Sokurenko

0
Rake::Task["test"].enhance do
  Rake::Task["test:cleanup"].invoke
end

1
谢谢Marcin。我也尝试过那种方法,但是在执行清理任务后测试仍然运行。它们按顺序调用,但第二个任务不等待第一个任务完成。 - Tyler Amos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接