簡體   English   中英

使用參數運行Rake任務

[英]Running a Rake task with parameters

我一直在努力通過隨附的規格獲得有關以下rake任務的測試報道。 但是,我似乎無法嘗試正確發送env參數嗎?

測試失敗

  1) myapp:database tasks myapp:database :recreate works
     Failure/Error: system("RAILS_ENV=#{args[:env]} rake db:create")

       main received :system with unexpected arguments
         expected: (/RAILS_ENV=testing rake db:drop/)
              got: ("RAILS_ENV=testing rake db:create")
       Diff:
       @@ -1,2 +1,2 @@
       -[/RAILS_ENV=testing rake db:drop/]
       +["RAILS_ENV=testing rake db:create"]

     # ./lib/tasks/database.rake:9:in `block (3 levels) in <top (required)>'
     # ./spec/lib/tasks/database_rake_spec.rb:17:in `block (5 levels) in <top (required)>'
     # ./spec/lib/tasks/database_rake_spec.rb:17:in `block (4 levels) in <top (required)>'
     # -e:1:in `<main>'

規格

describe 'myapp:database tasks' do
  include_context 'rake'
  let(:task_paths) { ['tasks/database', 'tasks/seed'] }

  # rubocop:disable RSpec/MultipleExpectations
  describe 'myapp:database' do
    before do
      invoke_task.reenable
    end

    # TODO!
    context ':recreate', focus: true do
      let(:task_name) { 'myapp:database:recreate' }

      it 'works' do
        expect_any_instance_of(Object).to receive(:system).with(/RAILS_ENV=testing rake db:drop/).and_return(true)
        expect { invoke_task.invoke('testing') }.to output(
          "\nDropping the testing database\n"\
          "\nCreating the testing database\n"\
          "\nRunning the testing database migrations\n"
        ).to_stdout
      end
    end

    # rubocop:disable RSpec/MessageSpies
    context ':reset' do
      let(:task_name) { 'myapp:database:reset' }

      it 'works' do
        expect(Rake::Task['myapp:database:recreate']).to receive(:invoke).twice
        expect(Rake::Task['myapp:seed:all']).to receive(:invoke)
        expect { invoke_task.invoke }.to output("\nResetting the development and testing databases\n").to_stdout
      end
    end
  end
  # rubocop:enable all
end

任務

namespace :myapp do
  namespace :database do
    if Rails.env.development? || Rails.env.test?
      desc 'Drop and create a database, ["env"] = environment'
      task :recreate, [:env] => [:environment]  do |_t, args|
        puts "\nDropping the #{args[:env]} database\n"
        system("RAILS_ENV=#{args[:env]} rake db:drop")
        puts "\nCreating the #{args[:env]} database\n"
        system("RAILS_ENV=#{args[:env]} rake db:create")
        puts "\nRunning the #{args[:env]} database migrations\n"
        system("RAILS_ENV=#{args[:env]} rake db:migrate")
      end

      desc 'Reset the db data and setup development'
      task reset: :environment do
        puts "\nResetting the development and testing databases\n"
        %w(development test).each do |db|
          Rake::Task['myapp:database:recreate'].invoke(db)
        end
        Rake::Task['myapp:seed:all'].invoke
      end
    end
  end
end

共享上下文

shared_context 'rake' do
  let(:invoke_task) { Rake.application[task_name] }
  let(:highline) { instance_double(HighLine) }

  before do
    task_paths.each do |task_path|
      Rake.application.rake_require(task_path)
    end
    Rake::Task.define_task(:environment)
  end

  before do
    allow(HighLine).to receive(:new).and_return(highline)
    # rubocop:disable all
    allow_any_instance_of(Object).to receive(:msg).and_return(true)
    allow_any_instance_of(Object).to receive(:error_msg).and_return(true)
    # rubocop:enable all
  end
end

更新資料

context ':recreate' do
  let(:task_name) { 'myapp:database:recreate' }

  it 'works' do
    expect_any_instance_of(Object).to receive(:system).with(/RAILS_ENV=testing rake db:drop/).and_return(true)
    expect_any_instance_of(Object).to receive(:system).with(/RAILS_ENV=testing rake db:create/).and_return(true)
    expect_any_instance_of(Object).to receive(:system).with(/RAILS_ENV=testing rake db:migrate/).and_return(true)
    expect { invoke_task.invoke('testing') }.to output(
      "\nDropping the testing database\n"\
      "\nCreating the testing database\n"\
      "\nRunning the testing database migrations\n"
    ).to_stdout
  end
end

正如我在評論中提到的,由於您在此處進行存根的方式,因此未從測試中調用任務:

    expect(Rake::Task['myapp:seed:all']).to receive(:invoke)

盡管此檢查是否invoke ,但實際上並沒有調用invoke (實際上,它使方法返回nil)。 要更改此設置,您可以:

  1. and_return(<something>)
  2. 堅持and_call_original

在這種情況下,可能要使用and_call_original因為您想調查任務中實際發生的情況。 為了在任務中存根單個方法調用,您一直使用的方法( expect_any_instance_of(Object).to receive(:system) )從技術上講是可行的,但可以將其重構為與代碼更分離。

例如,您可以將每個system調用分成其自己的方法(可用於rake任務),然后從測試中調用它們。 然后,為了存根,您只需要傳遞方法名稱即可。 如果需要,可以分別對每個方法進行單元測試,並將system調用期望值放在其中。

我不記得確切在哪里,但我聽說它建議不要在Rake任務中進行任何常規編程。 將您的代碼放在常規代碼庫中的某個位置,然后從rake任務中調用這些方法。 這可以看作是更通用模式的示例,該模式將大型方法重構為較小的方法。 這樣編寫代碼(以及功能樣式,但我不會講),使您的測試工作變得更輕松。


您的后續問題:

從測試用例的失敗消息中可以看到,實際和預期的唯一區別是一個是正則表達式,另一個是字符串。

一個簡單的解決方法是更改​​此行:

    expect_any_instance_of(Object).to receive(:system).with(/RAILS_ENV=testing rake db:drop/).and_return(true)

這樣with()參數是一個字符串,而不是正則表達式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM