2010-04-10 2 views
14

Я новичок в Ruby, и я пытался научиться Rake, RSpec и Cucumber. Я нашел код, который поможет мне проверить мои задачи Rake, но у меня возникли проблемы с его работой. Мне сказали, что здесь: http://blog.codahale.com/2007/12/20/rake-vs-rspec-fight/ бросить это:Тестирование задачи рейка в rspec (и огурце)

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 блоке в Invoke! ' /spec/spec_helper.rb: 20: in 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 –

ответ

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/задачи/хрон», если вы этого не сделаете иметь папку lib в вашем пути загрузки.

Я согласен с тем, что вы должны выполнять минимальную работу в задаче Rake и подталкивать остальные модели к простоте тестирования. Считаю, что мне важно убедиться, что код во время моих тестов интеграции ACTUALLY запускается в моих задачах cron, поэтому я считаю, что очень мягкое тестирование задач рейка оправдано.

+3

Я стараюсь использовать «выполнить» вместо вызова во время моих тестов , Специально, если много шагов зависят от проверки задачи рейка, это позволяет избежать возможности запуска задачи грабли один раз. Ссылка: http://stackoverflow.com/questions/2532427/why-is-rake-not-able-to-invoke-multiple-tasks-consecutively –

16

Поскольку тестирование рейка для меня слишком много, я стараюсь переместить эту проблему. Всякий раз, когда я нахожусь с длинной задачей рейка, которую хочу протестировать, я создаю модуль/класс в lib/ и перемещаю весь код из задачи там. Это оставляет задачу одной строкой кода Ruby, которая делегирует что-то более проверяемое (класс, модуль, вы называете его). Единственное, что остается непроверенным, заключается в том, вызывает ли команда rake правильную строку кода (и передает правильные параметры), но я думаю, что все в порядке.

Возможно, вам будет полезно сообщить нам, что является 21-й строкой вашего spec_helper.rb. Но учитывая, что подход, который вы опубликовали, углубляется в грабли (ссылаясь на его переменные экземпляра), я бы полностью отказался от него за то, что я предложил в предыдущем абзаце.

5

Я только что потратил немного времени на получение огурца, чтобы выполнить задачу грабли, поэтому я решил поделиться своим подходом. Примечание. Это использует Ruby 2.0.0 и Rake 10.0.4, но я не думаю, что поведение изменилось с предыдущих версий.

Это две части. Первое легко: с правильно настроенным экземпляром Rake::Application мы можем получить доступ к задачам на нем, вызвав #[] (например, rake['data:import']).После того, как мы имеем задачу мы можем запустить его, вызвав #invoke и передавая аргументы (например rake['data:import'].invoke('path/to/my/file.csv')

Вторая часть более неловко:.. Правильно создание экземпляра Rake::Application работать с После того, как мы сделали require 'rake' мы имеют доступ к модулю Rake.Он уже имеет экземпляр приложения, доступный от Rake.application, но он еще не настроен - он не знает ни одной из наших задач рейка. Однако он знает, где найти наш Rakefile, предполагая, что мы использовали один из стандартных имен файлов:. rakefile, Rakefile, rakefile.rb или Rakefile.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

поведение может изменились с тех пор, как был опубликован правильный ответ. У меня возникли проблемы с выполнением двух сценариев, необходимых для выполнения одной и той же задачи рейка (только один был выполнен, несмотря на то, что я использовал .execute вместо .invoke). Я решил поделиться своим подходом к решению проблемы (Rails 4.2.5 и Ruby 2.3.0).

Я отметил все сценарии, требующие грабли с @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

да, это было именно то, что нам нужно - спасибо! –

Смежные вопросы