2012-03-02 30 views
5

我生成動態基於在Rake文件現有的測試文件測試任務生成動態(基於現有的測試文件)耙測試任務。考慮你有以模式test_<name>.rb命名的各種單元測試文件。所以我正在做的是創建一個以'test'命名空間內的文件名命名的任務。 有了下面的代碼,然後我就可以調用所有的測試與rake test:<name>在Rake文件

require 'rake/testtask' 

task :default => 'test:all' 

namespace :test do 

    desc "Run all tests" 
    Rake::TestTask.new(:all) do |t| 
    t.test_files = FileList['test_*.rb'] 
    end 

    FileList['test_*.rb'].each do |task| 
    name = task.gsub(/test_|\.rb\z/, '') 
    desc "Run #{name} tests" 
    Rake::TestTask.new(:"#{name}") do |t| 
     t.pattern = task 
    end 
    end 

end 

上面的代碼工作,它似乎只是簡單的任務生成太多的代碼。 而我仍然沒有想出一種方式來打印一些描述文本到控制檯,如puts "Running #{name} tests:"

有沒有比上述方法更優雅的方式?

編輯:我真的有望獲得是循環的替代動態定義的任務,但我想耙LIB不提供任何幫助到,所以我堅持的循環。

+0

編輯@ScottJShea的提示代碼 – jasoares 2012-03-03 00:02:03

+0

對於那些不知道的人,Jim Weirich是Rake項目的作者,我感謝他的時間來回答我的問題。 – jasoares 2012-03-05 14:23:02

回答

13

下面是使用Rake中的規則解決問題的另一種方法。

每當rake想要構建「X」時,就會出現一個rake規則,它會找到一條規則說「構建X,使用Y」。我們將設置一個觸發規則,當某人以「test:XXX」格式指定目標時,它將嘗試使用名爲「test/test_XXX.rb」的文件。

require 'rake/testtask' 

task :default => 'test:all' 

TEST_FILES = FileList['test/test_*.rb'] 

namespace :test do 
    desc "Run all tests" 
    Rake::TestTask.new(:all) do |t| 
    t.test_files = TEST_FILES 
    end 

    rule /^test:/ => lambda { |tn| "test/test_%s.rb" % tn.gsub(/^test:/,'') } do |rule| 
    ruby rule.source 
    end 
end 

假設你有一個名爲 「測試/ test_my_code.rb」 測試文件。爲了執行該測試文件,只需鍵入:

rake test:my_code 

規則被觸發每當有開頭的目標「測試:」不能被任何其他任務相匹配。然後它查找由lamdba函數給出的文件。 lambda將目標名稱「test:XXX」轉換爲文件名「test/test_XXX.rb」。如果文件名存在,則執行規則的主體。

規則的主體只是將測試文件作爲可執行文件運行。這通常足以運行單個文件的測試。如果你需要的庫路徑(如「LIB」)添加到該測試的負載路徑,您可以更改規則身體要像

ruby "-Ilib", rule.source 

這和顯式循環的解決方案之間的另一個區別是,耙不會輸出規則的描述,所以「rake -T」輸出不會在其輸出中包含單個測試。

我不知道這是否比原來的更好,但它確實會給你一些選擇。

+0

感謝您接受我的請求,向我們介紹一些情況。我已經看到了規則的選擇,但是現在我完全明白了。 我接受了你的答案,因爲它是唯一一個展示環路解決方案的替代方案。正如你所說,在我看來,它有一個主要的缺點,因爲它不會生成rake -T的列表,而TestTask類不允許自定義描述。我打算在github上分享rake repo,並對其進行審查。同時,Rake :: TestTask中是否存在這樣的限制?再次感謝您接受我的挑戰。 – jasoares 2012-03-05 14:12:01

0

嗯...一個改變我做了所有我能想到的。不知道這是值得一個完整的答案,但我想確保我沒有腐敗的東西。您也可以嘗試張貼在Stack Exchange's Code Review

require 'rake/testtask' 

task :default => 'test:all' 

namespace :test do 

    desc "Run all tests" 
    Rake::TestTask.new(:all) do |t| 
    t.test_files = FileList['test_*.rb'] 
    end 

    FileList['test_*.rb'].each do |task| 
    name = task.gsub(/test_|\.rb\z/, '') 
    desc "Run #{name} tests" 
    Rake::TestTask.new(:"#{name}") do |t| 
     t.pattern = task 
    end 
    end 

end 
+0

我很欣賞提示,儘管我沒有找到那種改進。 – jasoares 2012-03-02 23:48:06

1

我的想法:

namespace :test do 

    FileList['test_*.rb'].each do |rakefile| 
    name = rakefile.gsub(/test_|\.rb\z/, '') 

    desc "Run #{name} tests" 
    task name do 
     require_relative rakefile 
    end 
    #Define default task for :test 
    task :default => name 
    end 

end 

desc "Run all tests" 
task :test => 'test:default' 
task :default => 'test' 

但我不知道這是否是require_relative更換Rake::TestTask.new一個好主意。

我的解決方案包含了另一個變化: 我更換task測試:所有with測試:默認and define a new task test`。

所以你rake -T得到follwoing結果:

rake test # Run all tests 
rake test:1 # Run 1 tests 
rake test:2 # Run 2 tests 

如果要運行所有測試,你需要rake test,具體測試可以rake test:<name>


做你可以使它也通過Rake::TestTask.new

require 'rake/testtask' 
namespace :test do 

    FileList['test_*.rb'].each do |rakefile| 
    name = rakefile.gsub(/test_|\.rb\z/, '') 

    Rake::TestTask.new(:"#{name}") do |t| 
     t.pattern = rakefile 
    end 
    #Define default task for :test 
    task :default => name 
    end 

end 

desc "Run all tests" 
task :test => 'test:default' 
task :default => 'test' 

隨着rake -T我得到:產生

rake test # Run all tests 
rake test:1 # Run tests for 1 
rake test:2 # Run tests for 2 

描述。

您可以添加:

desc 'Alternative description' 
    task name 

然後你得到:

rake test # Run all tests 
rake test:1 # Run tests for 1/Alternative description 
rake test:2 # Run tests for 2/Alternative description 

如果要更改文本,你可以的Rake::TestTask.newend之後添加

#replace description 
    Rake.application[name].comment.replace("Run #{name} tests") 

。這是醜陋的代碼,但Rake::TestTask不允許改變描述(這是可能的,但它將是類的修改)。

+0

感謝您的貢獻,我不太喜歡使用require_relative而不是Rake :: TestTask.new的想法,因爲TestTask添加了未來可能需要的更多功能(請參閱http://rake.rubyforge.org/classes /Rake/TestTask.html)。但是,我讚賞耙測試而不是耙測試的建議:全部。請檢查我的問題編輯進一步考慮。 – jasoares 2012-03-02 23:57:39

+0

我擴展了我的答案。 'FileList ['test _ *。rb']'還有一個循環,但只有一個。第二個是通過默認任務完成的。 – knut 2012-03-04 10:05:30

+0

請注意,您正在通過將每個單獨的測試作爲要求添加到默認任務來實現運行所有測試的目標。 +1用於顯示運行所有測試的不同方式,可以將它們全部或單獨運行。謝謝 – jasoares 2012-03-05 14:04:36