読者です 読者をやめる 読者になる 読者になる

( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

rspecの--tagオプションを利用して任意のコマンドライン引数をspec側に渡すという邪悪なhack

ruby rspec

今まで、rspecコマンドでは任意の引数を渡すことはできなかったので、環境変数経由で引き渡すという方法をとっていた。
( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

MY_OPT1=true rspec spec/my_spec.rb

環境変数で渡すのはダルいのでなんとかしたいと思い、`--tag`オプション経由で値を渡すというダーティなhackを書いた。

仕掛けは、helper.rbなどで、以下のように`Rspec.world.filter_manager.incusions`から引数を切り出してクラス変数に保持しておくようなアレをホゲる。

helper.rb

class MyOptions
  class << self
    OPTION_KEYS = [:my_opt1, :my_opt2]
    attr_accessor :options
    def parse(world)
      @options = world.filter_manager.inclusions.slice(*OPTION_KEYS)
    end
  end
end

RSpec.configure do |config|

  # filterをonに
  config.filter_run :focus => true
  config.run_all_when_everything_filtered = true

  # --tagから独自の引数を切り出して保持しておく
  MyOptions.parse(RSpec.world)
end

あとは、`MyOptions.options[:my_opt1]`のように参照できる。

my_options_spec.rb

require File.join(File.dirname(__FILE__), 'helper')

describe "MyOptions" do
  subject { MyOptions.options }

  it { should include(:my_opt1) }
  it { should include(:my_opt2) }
end


実行すると、`--tag`経由で引数が渡っていることが確認できる。

$ rspec spec/my_options_spec.rb -t my_opt1 -t my_opt2
Run options: include {:focus=>true, :my_opt1=>true, :my_opt2=>true}

All examples were filtered out; ignoring {:focus=>true, :my_opt1=>true, :my_opt2=>true}

MyOptions
  should include :my_opt1
  should include :my_opt2

Top 2 slowest examples (0.0029 seconds, 100.0% of total time):
  MyOptions should include :my_opt1
    0.00205 seconds ./spec/my_options_spec.rb:6
  MyOptions should include :my_opt2
    0.00085 seconds ./spec/my_options_spec.rb:7

Finished in 0.0034 seconds
2 examples, 0 failures


`--tag`渡さないとfailする。

$ rspec spec/my_options_spec.rb
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}

MyOptions
  should include :my_opt1 (FAILED - 1)
  should include :my_opt2 (FAILED - 2)

Failures:

  1) MyOptions should include :my_opt1
     Failure/Error: it { should include(:my_opt1) }
       expected {} to include :my_opt1
       Diff:
       @@ -1,2 +1 @@
       -[:my_opt1]

     # ./spec/my_options_spec.rb:6:in `block (2 levels) in <top (required)>'

  2) MyOptions should include :my_opt2
     Failure/Error: it { should include(:my_opt2) }
       expected {} to include :my_opt2
       Diff:
       @@ -1,2 +1 @@
       -[:my_opt2]

     # ./spec/my_options_spec.rb:7:in `block (2 levels) in <top (required)>'

Top 2 slowest examples (0.00381 seconds, 100.0% of total time):
  MyOptions should include :my_opt1
    0.00282 seconds ./spec/my_options_spec.rb:6
  MyOptions should include :my_opt2
    0.00099 seconds ./spec/my_options_spec.rb:7

Finished in 0.00432 seconds
2 examples, 2 failures

Failed examples:

rspec ./spec/my_options_spec.rb:6 # MyOptions should include :my_opt1
rspec ./spec/my_options_spec.rb:7 # MyOptions should include :my_opt2