在Rakefile中动态生成Rake测试任务(基于现有测试文件)

时间:2012-03-02 19:37:36

标签: ruby rake-task rakefile

我正在根据Rakefile中的现有测试文件动态生成测试任务。考虑您有以模式test_<name>.rb命名的各种单元测试文件。所以我正在做的是创建一个以'test'命名空间内的文件名命名的任务。 使用下面的代码,我可以使用rake test:<name>

调用所有测试
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:"

有比上述方法更优雅的方法吗?

编辑:我真正希望得到的是动态定义任务的循环的替代方案,但我想rake lib没有提供任何帮助,所以我坚持使用循环。

3 个答案:

答案 0 :(得分: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 / test_my_code.rb”的测试文件。要执行该测试文件,只需键入:

rake test:my_code

只要目标以“test:”开头且任何其他任务无法匹配,就会触发规则。然后它查找lamdba函数给出的文件。 lambda将目标名称“test:XXX”转换为文件名“test / test_XXX.rb”。如果文件名存在,则执行规则的主体。

规则的主体只是将测试文件作为可执行文件运行。这通常足以运行单个文件的测试。如果需要将库路径(例如“lib”)添加到测试的加载路径,则可以将规则体更改为类似

ruby "-Ilib", rule.source

这与显式循环解决方案之间的另一个区别是rake不会打印出规则的描述,因此“rake -T”输出将不包括其输出中的各个测试。

我不知道这是否比原版更好,但它确实为您提供了一些选择。

答案 1 :(得分: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'

但我不确定用Rake::TestTask.new替换require_relative是否是个好主意。

我的解决方案包含另一项更改: 我替换task测试:所有with测试:默认and define a new task测试。

因此,您可以使用rake -T获得以下结果:

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

如果您想更改文字,可以添加

    #replace description
    Rake.application[name].comment.replace("Run #{name} tests")
end Rake::TestTask.new之后

。这是丑陋的代码,但是Rake::TestTask不允许更改描述(这是可能的,但它将是对类的修改)。

答案 2 :(得分: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