2010-04-10 101 views
14

我是Ruby的新手,我一直在尝试学习Rake,RSpec和Cucumber。我发现了一些代码,可以帮助我测试我的Rake任务,但是我无法使其工作。我在这里告诉:http://blog.codahale.com/2007/12/20/rake-vs-rspec-fight/放弃这样的:在rspec(和黄瓜)中测试rake任务

def describe_rake_task(task_name, filename, &block) 
    require "rake" 

    describe "Rake task #{task_name}" do 
    attr_reader :task 

    before(:all) do 
     @rake = Rake::Application.new 
     Rake.application = @rake 
     load filename 
     @task = Rake::Task[task_name] 
    end 

    after(:all) do 
     Rake.application = nil 
    end 

    def invoke! 
     for action in task.instance_eval { @actions } 
     instance_eval(&action) 
     end 
    end 

    instance_eval(&block) 
    end 
end 

到我spec_helper.rb文件。

我已经成功了利用这个代码,并在我的黄瓜的步骤是这样运行:

When /^I run the update_installers task$/ do 
@rake = Rake::Application.new 
Rake.application = @rake 
load "lib/tasks/rakefile.rb" 
@task = Rake::Task["update_installers"] 

for action in @task.instance_eval { @actions } 
    instance_eval(&action) 
end 

instance_eval(&block) 

Rake.application = nil 
end 

但是当我试图把事情在rspec的工作,我得到以下错误。

引发ArgumentError在 'Rake任务 install_grapevine应该安装到 的mygrapevine目录'

错误的参数数目(1 2) /spec/spec_helper.rb:21:在instance_eval' /spec/spec_helper.rb: 21:in块调用! “ /spec/spec_helper.rb:20:在each' /spec/spec_helper.rb: 20:in invoke!' /spec/tasks/rakefile_spec.rb:12:in`块(2级)在 '

不幸的是,我刚下通过带红宝石的下一个星期了,所以元编程的东西是在我的头。任何人都可以将我指向正确的方向吗?

+0

相同没有RSpec:http://stackoverflow.com/questions/3530/how-do-i-rake-tasks-within-a-ruby-script – 2014-09-24 12:57:52

回答

19

这对我的作品:(Rails3中/红宝石1.9.2)

When /^the system does it's automated tasks$/ do  
    require "rake" 
    @rake = Rake::Application.new 
    Rake.application = @rake 
    Rake.application.rake_require "tasks/cron" 
    Rake::Task.define_task(:environment) 
    @rake['cron'].invoke 
end 

这里用您的耙子任务名称也注意到,您的要求可能是“LIB /任务/ cron的”如果你不在你的加载路径中有lib文件夹。

我同意你应该只在Rake任务中做最少的工作,并将剩下的工作推给模型以便于测试。话虽如此,我认为确保代码在我的集成测试中实际运行在我的cron任务中非常重要,所以我认为对rake任务进行非常温和的测试是合理的。

+3

我倾向于使用“执行”,而不是在我的测试过程中调用。特别是如果很多步骤都依赖于测试rake任务,这就避免了只能运行一次rake任务。参考:http://stackoverflow.com/questions/2532427/why-is-rake-not-able-to-invoke-multiple-tasks-consecutively – 2011-09-24 20:29:48

16

由于测试耙对我来说太多了,所以我倾向于解决这个问题。每当我发现自己需要测试一个长耙子任务时,我在lib/中创建一个模块/类,并将任务中的所有代码移到那里。这将任务留给一行Ruby代码,委托给更可测试的东西(类,模块,你命名它)。唯一没有经过测试的是rake任务是否调用了正确的代码行(并传递了正确的参数),但我认为这是可以的。

告诉我们这是spec_helper.rb的第21行可能会有帮助。但考虑到你发布的方法深入研究(参考其实例变量),我会完全放弃它,因为我在前面的段落中提到过。

5

我刚刚花了一点时间让黄瓜运行耙子任务,所以我想我会分享我的方法。注意:这是使用Ruby 2.0.0和Rake 10.0.4,但我认为自从以前的版本以来,行为已经发生了变化。

这有两个部分。首先很简单:通过正确设置Rake::Application的实例,我们可以通过调用#[](例如​​)访问该任务。一旦我们有一个任务,我们可以通过调用#invoke并传入参数(运行如rake['data:import'].invoke('path/to/my/file.csv')

第二部分是比较尴尬:。正确设置的Rake::Application实例一起工作一旦我们完成require 'rake'我们可以访问Rake模块,它已经有一个应用程序实例,可以从Rake.application获得,但它尚未设置 - 它不知道我们的任何rake任务,但它确实知道在哪里可以找到我们的Rakefile,假设我们使用了其中一个标准文件名:rakefile,Rakefile,rakefile.rbRakefile.rb

加载rakefile我们只需要d在应用程序上调用#load_rakefile,但在我们做到这一点之前,我们需要拨打#handle_options。对#handle_options的呼叫使用默认值填充options.rakelib。如果没有设置options.rakelib,那么#load_rakefile方法将爆炸,因为它预计options.rakelib是可枚举的。

这里的助手我已经结束了:

module RakeHelper 
    def run_rake_task(task_name, *args) 
    rake_application[task_name].invoke(*args) 
    end 

    def rake_application 
    require 'rake' 
    @rake_application ||= Rake.application.tap do |app| 
     app.handle_options 
     app.load_rakefile 
    end 
    end 
end 

World(RakeHelper) 

流行的代码到features/support/一个文件,然后只用run_rake_task在你的脚步,如:

When /^I import data from a CSV$/ do 
    run_rake_task 'data:import', 'path/to/my/file.csv' 
end 
3

的行为可能自发布正确答案以来已发生变化。执行两个需要运行相同rake任务的场景时遇到问题(尽管使用.execute而不是.invoke,但只执行一个场景)。我想分享我的方法来解决这个问题(Rails 4.2.5和Ruby 2.3.0)。

我用@rake标记了所有需要rake的场景,我定义了一个钩子来设置rake只有一次。

# hooks.rb 
Before('@rake') do |scenario| 
    unless $rake 
    require 'rake' 
    Rake.application.rake_require "tasks/daily_digest" 
    # and require other tasks 
    Rake::Task.define_task(:environment) 
    $rake = Rake::Task 
    end 
end 

(使用全局变量在这里建议:https://github.com/cucumber/cucumber/wiki/Hooks#running-a-before-hook-only-once

在步骤定义我简单地称为$rake

# step definition 
Then(/^the daily digest task is run$/) do 
    $rake['collector:daily_digest'].execute 
end 

欢迎任何的反馈。

+0

是的,这正是我们需要的修复 - 谢谢! – 2016-09-12 14:07:20