RspecのVersion2.11から
foo.should eq(bar)
foo.should_not eq(bar)
を
expect(foo).to eq(bar)
expect(foo).not_to eq(bar)
というように書くようになりました。
別にshouldを使った記法がなくなったわけではありませんが、
https://github.com/rspec/rspec-expectations
のREADME.mdには、もう新しいSyntaxの説明しか載っていないし、今後はexpectの方を使っていくほうがいいでしょう。
http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
には、新しいSyntaxを導入した背景が説明されています。
簡潔に書くと、shouldだとBasicObjectを継承したクラスのテストを書くときに不具合が起こるみたいですね。
移行方法
基本
基本的には、上に書いたように、
-
foo.should
をexpect(foo).to
に -
foo.should_not
をexpect(foo).not_to
に
置き換えるだけです。
比較演算子をとる
ただし、 shouldの後に直接オペレータをとる記法は使えなくなりました。
具体的には、
foo.should == bar
"a string".should_not =~ /a regex/
[1, 2, 3].should =~ [2, 1, 3]
foo.should < bar # <=, >, >= も同様
を
expect(foo).to eq bar
expect("a string").not_to match /a regex/
expect([1, 2, 3]).to match_array [2, 1, 3]
expect(foo).to be < bar # <=, >, >= も同様
のように変えます。
つまり、
-
==
の代わりにeq
- 正規表現関係の
=~
の代わりにmatch
- 配列の
=~
の代わりにmatch_array
を使えばいいんですね。
shouldの後に比較演算子<
をとる記法の代わりは、be <
というようにbe
を入れれば解決します。
should(to) less than
よりshould(to) be less than
の方が英語的に正しいので、これはこれでOKですね。
ブロックをとる
また、このexpect記法だと、ブロックをとることができるので、
lambda { do_something }.should raise_error(SomeError)
を
expect { something }.to raise_error(SomeError)
と書けるので、統一感があっていいですね。
移行が終わったら
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :expect # disables `should`
end
end
とすると、今後shouldを使った書き方ができなくなります。
ちなみにデフォルトでは
c.syntax = [:should, :expect] # enables both `should` and `expect`
と設定したのと同じになっています。
他のシチュエーションの書き方一覧
基本的に置き換えは上記の通り行うと済みますが、参照用に
https://github.com/rspec/rspec-expectations
に載っている他の書き方をそのまま転載しておきます。
Equivalence
expect(actual).to eq(expected) # passes if actual == expected
expect(actual).to eql(expected) # passes if actual.eql?(expected)
Note: The new expect
syntax no longer supports ==
matcher.
Identity
expect(actual).to be(expected) # passes if actual.equal?(expected)
expect(actual).to equal(expected) # passes if actual.equal?(expected)
Comparisons
expect(actual).to be > expected
expect(actual).to be >= expected
expect(actual).to be <= expected
expect(actual).to be < expected
expect(actual).to be_within(delta).of(expected)
Regular expressions
expect(actual).to match(/expression/)
Note: The new expect
syntax no longer supports =~
matcher.
Types/classes
expect(actual).to be_an_instance_of(expected)
expect(actual).to be_a_kind_of(expected)
Truthiness
expect(actual).to be_true # passes if actual is truthy (not nil or false)
expect(actual).to be_false # passes if actual is falsy (nil or false)
expect(actual).to be_nil # passes if actual is nil
Expecting errors
expect { ... }.to raise_error
expect { ... }.to raise_error(ErrorClass)
expect { ... }.to raise_error("message")
expect { ... }.to raise_error(ErrorClass, "message")
Expecting throws
expect { ... }.to throw_symbol
expect { ... }.to throw_symbol(:symbol)
expect { ... }.to throw_symbol(:symbol, 'value')
Yielding
expect { |b| 5.tap(&b) }.to yield_control # passes regardless of yielded args
expect { |b| yield_if_true(true, &b) }.to yield_with_no_args # passes only if no args are yielded
expect { |b| 5.tap(&b) }.to yield_with_args(5)
expect { |b| 5.tap(&b) }.to yield_with_args(Fixnum)
expect { |b| "a string".tap(&b) }.to yield_with_args(/str/)
expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2])
Predicate matchers
expect(actual).to be_xxx # passes if actual.xxx?
expect(actual).to have_xxx(:arg) # passes if actual.has_xxx?(:arg)
Ranges (Ruby >= 1.9 only)
expect(1..10).to cover(3)
Collection membership
expect(actual).to include(expected)
expect(actual).to start_with(expected)
expect(actual).to end_with(expected)
Examples
expect([1,2,3]).to include(1)
expect([1,2,3]).to include(1, 2)
expect([1,2,3]).to start_with(1)
expect([1,2,3]).to start_with(1,2)
expect([1,2,3]).to end_with(3)
expect([1,2,3]).to end_with(2,3)
expect({:a => 'b'}).to include(:a => 'b')
expect("this string").to include("is str")
expect("this string").to start_with("this")
expect("this string").to end_with("ring")