在“rake test”之后执行 rake 任务

Posted

技术标签:

【中文标题】在“rake test”之后执行 rake 任务【英文标题】:Executing a rake task after `rake test` 【发布时间】:2016-02-22 01:31:35 【问题描述】:

我正在尝试为 Rails 4.0.2 (Ruby 2.2.3) 项目创建一个 rake 任务,该任务创建测试数据库以及播种,然后运行测试套件,最后通过删除测试数据库进行清理。下面是一个简单的例子:

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 rake 任务完成运行之前调用了最后一个test:cleanup。之前的任务完成后是否还有调用cleanup rake任务?

这是使用跟踪运行任务的输出:

$ 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.

如您所见,任务是按顺序调用的,但清理任务是在测试完成之前执行的。有什么想法可以解决这个问题吗?

【问题讨论】:

【参考方案1】:

事实证明,这与 rake 的关系不大,而与 Minitest 执行其测试的方式有关。我在问题中提到,似乎以正确的顺序调用了 rake 任务,但由于某种原因稍后执行了测试。原因是 Minitest 使用 ruby​​ Kernel 方法at_exit 来执行测试。测试文件是在调用rake test 时读入的,但所有测试都在 ruby​​ 程序结束时执行,即使在我随后的 rake 任务之后也是如此。这里有一篇博客文章更详细地解释了这个问题:http://blog.arkency.com/2013/06/are-we-abusing-at-exit/。

【讨论】:

您找到解决方案了吗?【参考方案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 任务。所以它的调用时间比预期的要早。

【讨论】:

德米特里,这是个好主意,但结果相同。我真的觉得它与 rake 关系不大,而与 minitest 如何执行测试有关。 我在答案中添加了一些其他想法,可能您的 test:setuptest 已经调用了清理(不知道为什么,但也许您或某些 gem 添加了一个依赖项来运行 @ 987654330@),所以根本没有调用第二次。【参考方案3】:
Rake::Task["test"].enhance do
  Rake::Task["test:cleanup"].invoke
end

【讨论】:

谢谢马尔辛。我也尝试过这条路线,但是在执行清理任务后测试仍然运行。它们按顺序调用,但第二个任务不会等待第一个任务完成。

以上是关于在“rake test”之后执行 rake 任务的主要内容,如果未能解决你的问题,请参考以下文章

如何在'rake test'中关闭警告'ruby -w'?

自动执行 rake 任务以在 heroku 上启动时运行?

如何在 ruby​​ on rails 的亚马逊 aws 服务器中使用 gem 执行 rake 任务?

强制 Rake 任务在特定的 Rails 环境中运行

如何从 rake 任务中提前返回?

rake assets:precompile 突然失败