2010-04-10 10 views
14

Soy nuevo en Ruby, y he estado intentando aprender Rake, RSpec y Cucumber. Encontré un código que me ayudará a probar mis tareas de Rake, pero estoy teniendo problemas para que funcione. Me dijeron aquí: http://blog.codahale.com/2007/12/20/rake-vs-rspec-fight/ a caer esto:Prueba de una tarea de rake en rspec (y pepino)

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 

en mi archivo spec_helper.rb.

he logrado tomar el código y ejecutarlo en mis pasos de pepino así:

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 

pero cuando trato de hacer las cosas que trabajan en rspec, me sale el error siguiente.

ArgumentError en 'Rake tarea install_grapevine debe instalar en el directorio mygrapevine'

número incorrecto de argumentos (1 de 2) /spec/spec_helper.rb: 21: instance_eval' /spec/spec_helper.rb: 21:in en bloque en invoke! ' /spec/spec_helper.rb: 20: en each' /spec/spec_helper.rb: 20:in invoke! ' /spec/tasks/rakefile_spec.rb:12:in `bloque (2 niveles) en '

Por desgracia, tengo un poco menos de una semana de rubí bajo por la correa, por lo que el material es más metaprogramming mi cabeza. ¿Alguien podría señalarme en la dirección correcta?

+0

mismo sin RSpec: http://stackoverflow.com/questions/3530/how-do-i-rake-tasks-within-a-ruby-script –

Respuesta

19

Esto funciona para mí: (Rails3/Ruby 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 

sustituir el nombre de la tarea rake aquí y también en cuenta que su requieren pueden ser "lib/tareas/cron" si no lo hace tener la carpeta lib en tu ruta de carga.

Estoy de acuerdo en que solo debe hacer un trabajo mínimo en la tarea de Rake y pasar el resto a los modelos para facilitar las pruebas. Dicho esto, creo que es importante garantizar que el código se ejecute realmente en mis tareas cron durante mis pruebas de integración, por lo que creo que se justifica una prueba muy leve de las tareas de rake.

+3

Tiendo a utilizar "ejecutar" en lugar de invocar durante mis pruebas . Especialmente si muchos pasos dependen de la prueba de la tarea de rake, esto evita solo poder ejecutar la tarea de rake una vez. Ref: http://stackoverflow.com/questions/2532427/why-is-rake-not-able-to-invoke-multiple-tasks-consecutively –

16

Como probar el rastrillo es demasiado para mí, tiendo a mover este problema. Cada vez que me encuentro con una larga tarea de rake que quiero probar, creo un módulo/clase en lib/ y muevo todo el código de la tarea allí. Esto deja la tarea en una sola línea de código Ruby, que delega en algo más comprobable (clase, módulo, lo que sea). Lo único que queda sin comprobar es si la tarea de rake invoca la línea derecha de código (y pasa los parámetros correctos), pero creo que está bien.

Puede ser útil decirnos cuál es la línea 21 de su spec_helper.rb. Pero dado que el enfoque que publicaste profundiza en Rake (haciendo referencia a sus variables de instancia), lo abandonaría completamente por lo que sugerí en el párrafo anterior.

5

Acabo de pasar un tiempo obteniendo pepino para ejecutar una tarea de rake así que pensé en compartir mi enfoque. Nota: Esto está usando Ruby 2.0.0 y Rake 10.0.4, pero no creo que el comportamiento haya cambiado desde versiones anteriores.

Hay dos partes en esto. La primera es fácil: con una instancia correctamente configurada de Rake::Application, podemos acceder a las tareas llamando al #[] (por ejemplo, rake['data:import']).Una vez que tenemos una tarea que podemos ejecutarlo llamando #invoke y pasando los argumentos (por ejemplo rake['data:import'].invoke('path/to/my/file.csv')

La segunda parte es más torpe:.. Adecuadamente la creación de una instancia de Rake::Application trabajar con una vez que hemos hecho nos require 'rake' tener acceso al módulo Rake. Ya tiene una instancia de aplicación, disponible desde Rake.application, pero aún no está configurada, no conoce ninguna de nuestras tareas de rake. Sin embargo, sabe dónde encontrar nuestro Rakefile, asumiendo hemos utilizado uno de los nombres de archivo estándar:. rakefile, Rakefile, rakefile.rb o Rakefile.rb

para cargar el Rakefile acabamos nee d para llamar al #load_rakefile en la aplicación, pero antes de que podamos hacer eso tenemos que llamar al #handle_options. La llamada a #handle_options rellena options.rakelib con un valor predeterminado. Si options.rakelib no está configurado, el método #load_rakefile explotará, ya que espera que options.rakelib sea enumerable.

Aquí está el ayudante he terminado con:

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) 

Pop ese código en un archivo en features/support/ y luego sólo tiene que utilizar run_rake_task en sus medidas, por ejemplo:

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

El comportamiento podría han cambiado desde que se publicó la respuesta correcta. Estaba experimentando problemas al ejecutar dos escenarios que necesitaban ejecutar la misma tarea de rake (solo se estaba ejecutando uno a pesar de usar .execute en lugar de .invoke). Pensé compartir mi enfoque para resolver el problema (Rails 4.2.5 y Ruby 2.3.0).

Etiqueté todos los escenarios que requieren rastrillo con @rake y definí un gancho para configurar el rastrillo solo una vez.

# 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 

(Usando una variable global se sugiere aquí: https://github.com/cucumber/cucumber/wiki/Hooks#running-a-before-hook-only-once)

En la definición de paso lo llamé $rake

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

Cualquier comentario es bienvenido.

+0

sí, esa era exactamente la solución que necesitábamos, ¡gracias! –

Cuestiones relacionadas