RSpecをTest::Baseっぽく使う

RSpecでテストを書いていて単純なテストなんだけど、いろいろなデータで検証させたいといった場合に毎度毎度exampleを書くのがめんどくさいと思い、こんな感じでTest::Baseっぽく使えるやつを作ってみた。

describe Point, "detect_location" do
  with_fixtures :point => :location do
    filters({
      :point    => lambda { |val| Point.new(*val) },
      :location => :to_s,
    })

    it "should detect point :point to :location (:msg)" do |point, location|
      point.detect_location.should == location
    end

    set_fixtures([
      [ [1,   0]  => :right  ],
      [{[-1,  0]  => :left }, "border"  ],
      [{[-0.5,0]  => :left }, "inner" ],
      [ [0,   1]  => :top  ],
      [ [0,  -1]  => :bottom ],
    ])
  end
end

実行結果はこんな感じになる

Point detect_location
- should detect point ( 1, 0 ) to right () (FAILED - 6)
- should detect point ( -1, 0 ) to left (border) (FAILED - 7)
- should detect point ( -0.5, 0 ) to left (inner) (FAILED - 8)
- should detect point ( 0, 1 ) to top () (FAILED - 9)
- should detect point ( 0, -1 ) to bottom () (FAILED - 10)

6)
'Point detect_location should detect point ( 1, 0 ) to right ()' FAILED
expected: "right",
     got: "unknown" (using ==)
./examples/detect_location_spec.rb:47:

7)
'Point detect_location should detect point ( -1, 0 ) to left (border)' FAILED
expected: "left",
     got: "unknown" (using ==)
./examples/detect_location_spec.rb:47:

8)
'Point detect_location should detect point ( -0.5, 0 ) to left (inner)' FAILED
expected: "left",
     got: "unknown" (using ==)
./examples/detect_location_spec.rb:47:

9)
'Point detect_location should detect point ( 0, 1 ) to top ()' FAILED
expected: "top",
     got: "unknown" (using ==)
./examples/detect_location_spec.rb:47:

10)
'Point detect_location should detect point ( 0, -1 ) to bottom ()' FAILED
expected: "bottom",
     got: "unknown" (using ==)
./examples/detect_location_spec.rb:47:

with_fixturesの引数は省略すると{ :input => :expected }がデフォルトで使われる。
実はHashである必然性は全然ないのだけど、こう書けた方が視覚的にわかりやすいのでこう書くようにした。

filterは値がProcの場合はそれが実行され、Procじゃない場合は順番に__send__されて適用するようにしてみた。この辺は使ってみてまだ色々変わったりとかしそう。

set_fixturesで渡すデータをTest::Base互換で書けるようにするとか、exampleを複数書けるようにするとか、exampleがinput.should == expectedになるときは省略して書けるようにするとか、まだ色々やろうかなと思うことはあるのでgemにはしてないです。

いつものようにCodereposに入れてあるので色々アドバイスなり、いただけるとありがたいです。

http://coderepos.org/share/browser/lang/ruby/rspec-fixture/trunk