2010-04-10 82 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