🖥

#Rails + #rspec で rake を実行する方法を毎回忘れるので書き留めておく ( LoadError: Can't find

2019/11/25に公開

まとめ

  • 公式なやり方ではなく、あくまで内部メソッドやらをHackして利用するやり方っぽいので煩雑で使いにくいことは心える
  • rake_require で元のrake fileさえloadできたら勝ち
  • rake_require ではタスク名でも階層でもなく、単にファイル名とディレクトリパスを与えているところがポイント
  • 一度rake file をrequireしてしまえば、task invoke できる
  • うまくrequireできない場合は Rake.load_rakefile など内側のメソッドを使って、パスが正しいかどうかひたすらチェックせよ

rake

/app/lib/tasks/foo/bar.rake

namespace :foo do
  task bar: :environment do |task|
    SomeClass.run
  end
end

rspec

require "rails_helper"
require "rake"

describe do
  before(:all) do
    @rake = Rake::Application.new
    Rake.application = @rake

    # This line require file e.g '/app/lib/tasks/foo/bar.rake'
    Rake.application.rake_require('bar', [Rails.root.join('lib', 'tasks', 'foo')])

    Rake::Task.define_task(:environment)
  end

  before(:each) do
    @rake[task].reenable
  end

  describe  do
    # Do not use dot
    # BAD CASE : foo.bar 
    let(:task) { 'foo:bar' }

    it do
      expect(SomeClass).to receive(:run)
      @rake[task].invoke
    end
  end
end

Doc

https://apidock.com/ruby/v1_9_3_392/Rake/Application/rake_require

File lib/rake/application.rb, line 452

def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
  fn = file_name + ".rake"
  return false if loaded.include?(fn)
  paths.each do |path|
    full_path = File.join(path, fn)
    if File.exist?(full_path)
      Rake.load_rakefile(full_path)
      loaded << fn
      return true
    end
  end
  fail LoadError, "Can't find #{file_name}"
end

Ref

Rspecでrake taskをテストする方法  - Qiita
Rakeタスクのテストの仕方 - Qiita
[Ruby on Rails]RSpecによるRakeのテスト | Developers.IO

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2767

チャットメンバー募集

何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ

Twitter

https://twitter.com/YumaInaura

公開日時

2019-11-25

Discussion