我尝试在rspec中为两个rake任务编写测试,这两个任务定义在同一个文件中(在Rails 3.0.11项目中)。由于某种原因,只有其中一个通过了测试。我编写了一个小的演示来抽象任务的实际内容,同样的事情发生了。当从命令行使用rake
调用时,两个任务都工作。这是怎么回事?下面是我的演示:
库/任务/演示任务.rake
namespace :demo do
task :test => :environment do
puts "test!"
end
task :test_two => :environment do
puts "second test!"
end
end
规范/库/任务/演示规范.rb
require 'spec_helper'
require 'rake'
describe "test tasks" do
let(:rake) do
app = Rake::Application.new
app.options.silent = true
app
end
before :each do
Rake.application = rake
Rake.application.rake_require 'lib/tasks/demo_tasks',
[Rails.root.to_s]
Rake::Task.define_task :environment
end
describe "demo:test" do
it "runs" do
rake["demo:test"].invoke
end
end
describe "demo:test_two" do
it "also_runs" do
rake["demo:test_two"].invoke
end
end
end
rspec规范/库/任务/演示规范.rb
test tasks
demo:test
test!
runs
demo:test_two
also_runs (FAILED - 1)
Failures:
1) test tasks demo:test_two also_runs
Failure/Error: rake["demo:test_two"].invoke
RuntimeError:
Don't know how to build task 'demo:test_two'
# ./spec/lib/tasks/demo_spec.rb:26:in `block (3 levels) in <top (required)>'
3条答案
按热度按时间wgx48brx1#
before
更改为before :all
(而不是:each
)。rake_require
。$"
是一个Ruby特殊变量,用于保存require
加载的模块数组。如果不传递可选参数,
rake_require
将使用Ruby加载的模块数组,这意味着模块不会再次加载:Ruby知道模块被加载了,rake检查Ruby知道什么,对于每个测试它都是一个新的rake示例。切换到
before :all
是有效的,因为这意味着let
块只运行一次:一个RAKE示例、一个模块加载,每个人都很高兴。尽管如此,为什么要重新加载rake环境两次呢?您的目标是测试您的任务,这并不需要为每个规范都提供一个新的rake上下文。
您可以以每个规范中的一些小的冗长为代价,完全消除局部变量:
您可以在
before
块中定义一个示例变量,以避免Rake::Task
引用:IMO,由于多种原因不太理想。Here's a summary I agree with。
pxy2qtax2#
一个流行的搜索引擎引导我来到这里,因为在我的案例中,当
#invoke
在一个给定的测试中被多次使用时,我看到测试失败了。出现此问题的原因是在编写时(Rake v12),
#invoke
* 仅运行一次 * 任务,因此例如:...如果测试写得很好并且任务调用正确,那么无论哪个
it
首先运行,都可能通过,但是对于第二个it
,总是会失败,因为在给定的Rake.application
中,使用#invoke
只运行一次任务。是的,这确实意味着 * 至少在Rake v12* 下测试,许多在线文章显示如何测试Rake任务是(fo)不正确的,或者侥幸逃脱,因为他们只显示了一个单一的测试,任何给定的任务在他们的例子。
我们可以使用Rake的
#execute
,但它不运行相关任务,因此会导致它自己的一系列问题,并使我们进一步远离测试Rake堆栈,就好像它是在命令行上调用的一样。相反,将公认的答案与网上的其他零碎信息混合在一起,得出了这样的选择:
before :each
上准备Rake。Rake.application
;这意味着我们可以在任何数量的测试中使用invoke
,尽管在任何单个测试中仅使用一次。Rake.application
开箱即用的示例,我们可以在设置所有路径等时只写Rake.application.rake_require 'tasks/demo_tasks'
,但由于我们肯定需要为每个测试提供一个新的Rake应用程序示例,以避免在测试中“弄脏”它的状态,因此需要来自@dave-newtown的“手写”表单。Rake.application.invoke_task
而不是Rake::Task[...].invoke
,这使得参数的语法与Rake命令行上使用的语法相同,我觉得这是一种更“准确”和自然的测试使用参数的任务的方法。是的,这确实意味着 * 至少在Rake v12* 下测试时,许多在线文章显示如何测试Rake任务是不正确的,或者因为它们只显示了示例中任何给定任务的单个测试而侥幸逃脱。很可能早期的Rake版本没有这样做,所以这些文章在编写时是正确的。
希望有人觉得这有帮助。
参考文献:
(搜索引擎提示:测试rake rspec测试调用已调用仅运行一次)
8iwquhpp3#
Rake跟踪哪些任务已经运行过,并假设您只想运行它们一次。一个简单的解决方案是在调用任务之前,在
before(:each)
钩子中调用任务上的#reenable
。例如,假设Rake任务应该调用SomeClass上的两个方法,并且您想在单独的示例中测试它们: