RSpec3.1の主な変更点をまとめてみた
もう1週間経ってしまいましたがRSpec3.1がリリースされたので勉強がてら主な新機能・変更点をまとめてみました。
なお、この記事はMyron Marstonの記事の要約になっています。
Backtraceフィルタの変更
RSpec3.0では表示していなかったgemの中のbacktraceをデフォルトで表示するようになっています。
非表示にする場合は以下を設定します。
RSpec.configure do |config|
config.backtrace_exclusion_patterns << /gems/
end
特定のgemのbacktraceを非表示にすることもできます。
RSpec.configure do |config|
config.filter_gems_from_backtrace "rack", "rake"
end
–exclude-patternオプションの追加
$ rspec --pattern "spec/**/*_spec.rb" --exclude-pattern "spec/acceptance/**/*_spec.rb"
という感じで除外するspecファイルを指定できます。
Rakefileに書くとこうなります。
require 'rspec/core/rake_task'
desc "Run all but the acceptance specs"
RSpec::Core::RakeTask.new(:all_but_acceptance) do |t|
t.exclude_pattern = "spec/acceptance/**/*_spec.rb"
end
スタンドアロンでも設定なしで動く
RSpec3.0のデフォルト設定ではrspec-expectationやrspec-mocksがないとロード失敗でエラーになっていました。
RSpec3.1ではロードできなくてもエラーが起きないようになっていて、spec-coreだけで使いやすくなっています。
.rspecを–warningsフラグtrueで生成しない
RailsでWarningがたくさん出てしまうという理由で、Railsで.rspec
を自動生成した時の--warnings
のデフォルト値をtrue
にしないようになっています。
have_attributesマッチャの追加
オブジェクトのattributeテストを簡単に行えるhave_attributes
マッチャが追加されています。
Person = Struct.new(:name, :age)
person = Person.new("Alice", 20)
expect(person).to have_attributes(name: "Alice", age: 20)
このマッチャはan_object_having_attributes
にもエイリアスされていて
people = [Person.new("Alice", 20), Person.new("Bob", 30)]
expect(people).to match([
an_object_having_attributes(name: "Alice", age: 20),
an_object_having_attributes(name: "Bob", age: 30)
])
という使い方もできます。
メソッドへ渡るメッセージにも使えるようです。
expect(article).to receive(:author=).with(
an_object_having_attributes(name: "Alice")
)
Compoundマッチャをブロックでも利用可能
以下のように1つのブロックに対して複数のマッチャを続けて書くことができます。
x = y = 0
expect {
x += 1
y += 2
}.to change { x }.to(1).and change { y }.to(2)
define_negated_matcherの追加
例えばexclude
をinclude
の反対として定義できます。
RSpec::Matchers.define_negated_matcher :exclude, :include
こうすると
expect(odd_numbers).not_to include(14)
の代わりに
expect(odd_numbers).to exclude(14)
と書けるようになります。
この機能はCompoundマッチャと組み合わせると非常に便利です。
adults = Town.find("Springfield").adults
marge = Character.find("Marge")
bart = Character.find("Bart")
expect(adults).to include(marge).and exclude(bart)
カスタムマッチャチェインをdescriptionにも出力
Spec::Matchers.define :be_smaller_than do |max|
chain :and_bigger_than do |min|
@min = min
end
match do |actual|
actual < max && actual > @min
end
end
# usage:
expect(10).to be_smaller_than(20).and_bigger_than(5)
のようなカスタムマッチャがあった場合、RSpec3.0だとこのようなメッセージが出力されていました。
Failure/Error: expect(5).to be_smaller_than(10).and_bigger_than(7)
expected 5 to be smaller than 10
RSpec3.1では次のようになります。
Failure/Error: expect(5).to be_smaller_than(10).and_bigger_than(7)
expected 5 to be smaller than 10 and bigger than 7
ただし、この機能は後方互換のためにデフォルトoffになっているので
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
end
を設定する必要があります。
RSpec4からはデフォルトでonになるようです。
*_spyメソッドの追加
これまでdoubleを使う時にnil
を返すだけのメソッドでも
spy = double(:foo => nil)
expect(spy).to have_received(:foo)
というようにメソッド名(:foo
)を2回書かなければいけませんでした。
RSpec3.1ではas_null_object
メソッドが追加されて
spy = double.as_null_object
expect(spy).to have_received(:foo)
というようにメソッド名を1回だけ書けば済むようになっています。
また、as_null_object
をいちいち書かなくてもいいように下記のメソッドが用意されています。
spy(...) # double(...).as_null_object と同じ
instance_spy(...) # instance_double(...).as_null_object と同じ
class_spy(...) # class_double(...).as_null_object と同じ
object_spy(...) # object_double(...).as_null_object と同じ
and_wrap_originalの追加
and_wrap_original
を使うとテスト時にメソッドをラップできるようになります。
allow(api_client).to receive(:fetch_users).and_wrap_original do |original_method, *args|
original_method.call(*args).first(10) # テスト時は10ユーザだけ取得する
end
Rails4.2のサポート
Rails3.1は公式にRails4.2をサポートするとのことです。
rails_helper.rbではspec/supportを自動ロードしない
spec/support
を全てロードすると時間がかかるため、自動生成されたrails_helper.rb
ではspec/support
を自動ロードしないようになっています。
RSpec3.1では必要なファイルだけロードすることが推奨されています。
まとめ
以上、RSpec3.1の新機能の紹介でした。
個人的にはdefine_negated_matcher
が活躍してくれそうな気がしてます。