为什么我的 rake 任务 运行 在我的测试中是两次?
Why is my rake task running twice in my test?
我有一个 rake 任务测试,我按照我能在网上找到的唯一示例进行设置。
看起来像这样:
require 'test_helper'
require 'minitest/mock'
require 'rake'
class TestScrapeWelcome < ActiveSupport::TestCase
def setup
Rake.application.init
Rake.application.load_rakefile
@task = Rake::Task['scrape:scrape']
@task.reenable
end
def teardown
Rake::Task.clear
end
test "scraping text and sending to elasticsearch" do
mocked_client = Minitest::Mock.new
get_fixtures.each_with_index do |arg,i|
mocked_client.expect :index, :return_value, [index: "test", type: 'welcome', id: i, body: arg]
end
Elasticsearch::Model.stub :client, mocked_client do
@task.invoke
end
assert mocked_client.verify
end
private
def get_fixtures
(0..11).map { |i|
File.read("test/fixtures/scrape/index_#{i}.json")
}
end
end
但是在任务 运行s 一旦它开始 运行ning 之后,我没有做任何事情(puts
在 @task.invoke
之前和之后打印表明任务只是运行一次)。
原来在测试运行时已经需要并初始化了 rake,因此需要删除以下所有行,或者任务被定义两次并运行两次,即使您只调用它一次也是如此。
require 'minitest/mock'
require 'rake'
...
Rake.application.init
Rake.application.load_rakefile
rails 5.1 的更新答案(使用 minitest):
我发现我需要以下内容来一次且仅一次加载任务:
MyAppName::Application.load_tasks if Rake::Task.tasks.empty?
或者将 MyAppName::Application.load_tasks
添加到您的 test_helper,如果您不介意加载任务,即使 运行 个不需要它们的单独测试。
(将 MyAppName 替换为您的应用程序名称)
用于测试 Gem 的任务的解决方案已成为 Railtie
,因此它可以将任务添加到 Rails 应用程序:
当您还在 spec_helper.rb
中定义 Rails::Application
class 时,不要在测试模式中定义 Railtie
(这允许您的测试调用 Rails.application.load_tasks
).否则 Rake 文件将作为 Railtie 加载一次,作为引擎加载一次:
class Railtie < Rails::Railtie
rake_tasks do
load 'tasks/mygem.rake'
end
end unless Rails.env.test? # Without this condition tasks under test are run twice
另一种解决方案是在 Rake 文件中添加一个条件,以便在文件已加载的情况下跳过任务定义。
我试过@iheggie 的回答,但它的工作方式确实测试了 运行 一次,但任何其他任务都与 Don't know how to build task '<task_name_like_db_migrate>'
中断了。
我还在 Rails 3.2。结果是事先加载了几个任务,所以 Rake::Task.tasks.empty?
从来没有 true
并且所有其他有用的任务都没有加载。我摆弄过它,这个版本现在对我有用:
Rake::Task.clear if Rails.env.test?
MyAppName::Application.load_tasks
希望这对任何人都有帮助。
我有一个 rake 任务测试,我按照我能在网上找到的唯一示例进行设置。
看起来像这样:
require 'test_helper'
require 'minitest/mock'
require 'rake'
class TestScrapeWelcome < ActiveSupport::TestCase
def setup
Rake.application.init
Rake.application.load_rakefile
@task = Rake::Task['scrape:scrape']
@task.reenable
end
def teardown
Rake::Task.clear
end
test "scraping text and sending to elasticsearch" do
mocked_client = Minitest::Mock.new
get_fixtures.each_with_index do |arg,i|
mocked_client.expect :index, :return_value, [index: "test", type: 'welcome', id: i, body: arg]
end
Elasticsearch::Model.stub :client, mocked_client do
@task.invoke
end
assert mocked_client.verify
end
private
def get_fixtures
(0..11).map { |i|
File.read("test/fixtures/scrape/index_#{i}.json")
}
end
end
但是在任务 运行s 一旦它开始 运行ning 之后,我没有做任何事情(puts
在 @task.invoke
之前和之后打印表明任务只是运行一次)。
原来在测试运行时已经需要并初始化了 rake,因此需要删除以下所有行,或者任务被定义两次并运行两次,即使您只调用它一次也是如此。
require 'minitest/mock'
require 'rake'
...
Rake.application.init
Rake.application.load_rakefile
rails 5.1 的更新答案(使用 minitest):
我发现我需要以下内容来一次且仅一次加载任务:
MyAppName::Application.load_tasks if Rake::Task.tasks.empty?
或者将 MyAppName::Application.load_tasks
添加到您的 test_helper,如果您不介意加载任务,即使 运行 个不需要它们的单独测试。
(将 MyAppName 替换为您的应用程序名称)
用于测试 Gem 的任务的解决方案已成为 Railtie
,因此它可以将任务添加到 Rails 应用程序:
当您还在 spec_helper.rb
中定义 Rails::Application
class 时,不要在测试模式中定义 Railtie
(这允许您的测试调用 Rails.application.load_tasks
).否则 Rake 文件将作为 Railtie 加载一次,作为引擎加载一次:
class Railtie < Rails::Railtie
rake_tasks do
load 'tasks/mygem.rake'
end
end unless Rails.env.test? # Without this condition tasks under test are run twice
另一种解决方案是在 Rake 文件中添加一个条件,以便在文件已加载的情况下跳过任务定义。
我试过@iheggie 的回答,但它的工作方式确实测试了 运行 一次,但任何其他任务都与 Don't know how to build task '<task_name_like_db_migrate>'
中断了。
我还在 Rails 3.2。结果是事先加载了几个任务,所以 Rake::Task.tasks.empty?
从来没有 true
并且所有其他有用的任务都没有加载。我摆弄过它,这个版本现在对我有用:
Rake::Task.clear if Rails.env.test?
MyAppName::Application.load_tasks
希望这对任何人都有帮助。