2012-03-02 17 views
5

Estoy generando tareas de prueba dinámicamente basadas en archivos de prueba existentes en un Rakefile. Considere que tiene varios archivos de prueba de unidad nombrados después del patrón test_<name>.rb. Entonces, lo que estoy haciendo es crear una tarea con el nombre del nombre del archivo dentro del espacio de nombres 'prueba'. Con el código de abajo que a continuación se puede llamar a todas las pruebas con rake test:<name>Genere tareas de prueba de Rake de forma dinámica (en base a archivos de prueba existentes) en un Rakefile

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 

funciona El código anterior, apenas se parece demasiado código para la generación tarea sencilla. Y todavía no han encontrado una manera de imprimir alguna descripción de texto a la consola como puts "Running #{name} tests:"

¿Hay una manera más elegante que el método anterior?

EDIT: Lo que realmente esperaba obtener era una alternativa al bucle para definir las tareas de forma dinámica pero supongo que el lib rastrillo no proporciona ninguna ayuda para que así que estoy atascado con el bucle.

+0

Editado el código desde la punta de @ScottJShea – jasoares

+0

Para aquellos que no saben, Jim Weirich es el autor del proyecto Rake, agradezco su tiempo para responder a mi pregunta a continuación. – jasoares

Respuesta

13

Aquí hay otra forma de resolver el problema usando las reglas en Rake.

Una regla de rake entra en juego cada vez que Rake quiere construir "X", y encuentra una regla que dice "para construir X, use Y". Configuraremos una regla que se active cuando alguien especifique un objetivo en el formato "prueba: XXX", intentará usar un archivo llamado "prueba/prueba_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 

Supongamos que tiene un archivo de prueba llamado "test/test_my_code.rb". Para ejecutar ese archivo de prueba, basta con escribir:

rake test:my_code 

La regla se activa cada vez que hay un objetivo que comienza con "prueba" de que no se puede igualada por ninguna otra tarea. Luego busca un archivo dado por la función lamdba. El lambda transforma el nombre de destino "prueba: XXX" en un nombre de archivo "test/test_XXX.rb". Si el nombre de archivo existe, se ejecuta el cuerpo de la regla.

El cuerpo de la regla solo ejecuta el archivo de prueba como un archivo ejecutable. Esto es generalmente suficiente para ejecutar las pruebas de un solo archivo. Si es necesario agregar rutas de biblioteca (por ejemplo, "lib") a la trayectoria de la carga de las pruebas, se puede cambiar el cuerpo regla a ser algo así como

ruby "-Ilib", rule.source 

Otra diferencia entre esta y la solución de bucle explícito es que el rastrillo no imprimirá las descripciones de las reglas, por lo que la salida "rake -T" no incluirá las pruebas individuales en su salida.

No sé si esto es mejor que el original, pero le da algunas opciones.

+0

Gracias por aceptar mi solicitud para arrojar algo de luz sobre nosotros. Ya había visto la regla alternativa, pero solo ahora la entendía completamente. Acepté su respuesta ya que era la única que mostraba una alternativa a la solución de bucle. Como dijiste, tiene, en mi opinión, un retroceso importante ya que no genera una lista para el rake -T y la clase TestTask no permite personalizar la descripción. Tengo la intención de bifurcar el repositorio de rake en github y echar un vistazo a eso. Mientras tanto, ¿hay alguna razón para tales limitaciones en Rake :: TestTask? Una vez más, muchas gracias por aceptar mi desafío. – jasoares

0

Hmmm ... el único cambio que hice fue todo lo que pude pensar. No estoy seguro de que valga la pena una respuesta completa, pero quería asegurarme de no haber corrompido nada. También puede intentar enviar en 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

Aprecio la sugerencia, aunque no era ese tipo de mejora lo que estaba buscando. – jasoares

1

Mi idea:

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' 

Pero no estoy seguro de si es una buena idea para reemplazar Rake::TestTask.new con require_relative.

Mi solución contiene otro cambio: puedo reemplazar task test: all with prueba: por defecto and define a new task test`.

para que pueda obtener el resultado follwoing con rake -T:

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

Si desea ejecutar todas las pruebas, es necesario rake test, pruebas específicas se puede hacer con rake test:<name>


Usted puede hacerlo también a través de 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' 

Con rake -T me sale: se genera

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

La descripción.

puede añadir un:

desc 'Alternative description' 
    task name 

A continuación, se obtiene:

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

Si desea cambiar el texto que puede añadir

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

después de la end de Rake::TestTask.new. Es un código feo, pero Rake::TestTask no permite cambiar la descripción (sería posible, pero sería una modificación de la clase).

+0

Gracias por su contribución, realmente no me gusta la idea de usar require_relative en lugar de Rake :: TestTask.new ya que TestTask agrega más funcionalidades que pueden ser necesarias en el futuro (ver http://rake.rubyforge.org/classes /Rake/TestTask.html). Sin embargo, aprecié la sugerencia de la prueba de rake en lugar de la prueba de rake: todos. Plese verifique mi edición de preguntas para más consideraciones. – jasoares

+0

He extendido mi respuesta. Todavía hay un bucle con 'FileList ['test _ *. Rb']', pero solo uno. El segundo se realiza a través de la tarea predeterminada. – knut

+0

Observe que está logrando el objetivo de ejecutar todas las pruebas al agregar cada prueba individual como un requisito para la tarea predeterminada. +1 para mostrar diferentes formas de ejecutar todas las pruebas, ya sea ejecutándolas juntas o por separado. Gracias – jasoares

Cuestiones relacionadas