7

同じファイル (Rails 3.0.11 プロジェクト) で定義されている 2 つの rake タスクのテストを rspec で記述しようとしています。なぜか片方しか通らない。タスクの実際の内容を抽象化するために小さなデモを書きましたが、同じことが起こります。どちらのタスクもrake、コマンド ラインから呼び出すと機能します。どうしたの?これが私のデモです:

lib/tasks/demo_tasks.rake

namespace :demo do
  task :test => :environment do
    puts "test!"
  end

  task :test_two => :environment do
    puts "second test!"
  end
end

spec/lib/tasks/demo_spec.rb

require 'spec_helper'
require 'rake'

describe "test tasks" do
  let(:rake) do
    app = Rake::Application.new
    app.options.silent = true
    app
  end

  before :each do
    Rake.application = rake
    Rake.application.rake_require 'lib/tasks/demo_tasks',
                                  [Rails.root.to_s]
    Rake::Task.define_task :environment
  end

  describe "demo:test" do
    it "runs" do
      rake["demo:test"].invoke
    end
  end

  describe "demo:test_two" do
    it "also_runs" do
      rake["demo:test_two"].invoke
    end
  end
end

rspec spec/lib/tasks/demo_spec.rb

test tasks
  demo:test
test!
    runs
  demo:test_two
    also_runs (FAILED - 1)

Failures:

  1) test tasks demo:test_two also_runs
     Failure/Error: rake["demo:test_two"].invoke
     RuntimeError:
       Don't know how to build task 'demo:test_two'
     # ./spec/lib/tasks/demo_spec.rb:26:in `block (3 levels) in <top (required)>'
4

2 に答える 2

9

一言beforeで言えば、あなたをbefore :all(の代わりに)に変更してください:each

または:空の配列を 3 番目のパラメーターとして に渡しますrake_require

Rake.application.rake_require 'lib/tasks/demo_tasks', 
                              [Rails.root.to_s], 
                              []

詳細

def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
  fn = file_name + ".rake"
  return false if loaded.include?(fn)
  ...

$"によってロードされたモジュールの配列を保持する Ruby の特殊変数ですrequire

オプションのパラメーターを渡さない場合rake_require、Ruby によって読み込まれたモジュールの配列が使用されます。これは、モジュールが再度読み込まれないことを意味します。Ruby はモジュールが読み込まれたことを認識し、Ruby が認識していることを確認するために rake チェックを行い、テストごとに新しい rake インスタンスになります。

before :allブロックが一度だけ実行されたことを意味するため、への切り替えは機能しましletた: 1 つのレーキ インスタンス、1 つのモジュール ロード、誰もが満足しています。

とはいえ、なぜ rake 環境を 2 回リロードするのでしょうか? あなたの目標は、タスクをテストすることです。これには、仕様ごとに新しい rake コンテキストは必要ありません。

各仕様の多少の冗長性を犠牲にして、ローカルを完全に削除できます。

describe "test tasks" do
  before :all do
    Rake.application = Rake::Application.new
    Rake.application.rake_require 'lib/tasks/demo_tasks', [Rails.root.to_s]
    Rake::Task.define_task :environment
  end

  describe "demo:test" do
    it "runs" do
      Rake::Task["demo:test"].invoke
    end
  end
end

ブロックでインスタンス変数を定義して、参照beforeを回避できます。Rake::Task

before :all do
  @rake = Rake::Application.new
  Rake.application = @rake
  Rake.application.rake_require 'lib/tasks/demo_tasks', [Rails.root.to_s]
  Rake::Task.define_task :environment
end

describe "demo:test" do
  it "runs" do
    @rake["demo:test"].invoke

IMO、多くの理由であまり望ましくありません。ここに私が同意する要約があります。

于 2012-09-09T00:09:41.017 に答える