「it」メソッドにブロックを渡さず保留にすることもできますが、ブロックを実装しかかったサンプルを「保留」にしたいときは「pending」メソッドまたは「skip」メソッドを使います。
「pending」メソッドは、その実装しかかった振る舞いをチェックしエラーが発生すると「保留のサンプル」として扱われます。しかし、もしチェックをパスすると、それは「失敗」として扱われます。
一方の「skip」はそういった「しかかり」のチェックなしで「保留」とすることができます。RSpec 3より前は「pending」が「skip」として動作していました。
it "will be deleted when user deleted" do skip # or pending end #=> Pending: Borrowing will be deleted when user deleted # Not yet implemented # ./spec/models/borrowing_spec.rb:18
あるサンプルグループにおいて各「サンプル(example)」の共通の処理をまとめておく「フック」と呼ばれる仕組みがRSpecには用意されています。フックにはサンプルの前に実行する「before」フック、後に実行する「after」フック、ブロックを定義してその中でサンプルを実行する「around」フックがあります。
よく使う「before」フックの例を示します。
describe '#overdue?' do context 'due_back is tomorrow' do before do @borrowing = Borrowing.new(due_back: 1.days.since) end it "returns false when attribute is default(today)" do expect(@borrowing.overdue?).to be(false) end it "returns true when attribute is 2 days later" do expect(@borrowing.overdue?(2.days.since)).to be(true) end end end
また各フックのメソッドは、サンプルごとに1回行う場合は「:each」、サンプルグループの前に一回行う場合は「:all」の引数を取ることができます。デフォルトでは「:each」を取るようになっています。
アプリケーションの振る舞いを定義するとき、「サンプル(example)」の一つ一つには起こるべきことを記述します。これは「エクスペクテーション」と呼ばれ、一般に次の記法で書かれます。
expect(items).to include(item)
このエクスペクテーションはコンテナーオブジェクトの「items」に「item」が含まれていることを期待しています。
より細かく見ていくと、「expect」メソッドは振る舞いを期待するオブジェクトを引数に取ります。そしてメソッドチェーンしている「to」メソッドは「マッチャー」と呼ばれるRSpecのメソッドを引数に取ります。
このマッチャーとは、期待するオブジェクトと振る舞いが適合するかを調べるメソッドです。多様なマッチャーが用意されており、例として以下にいくつか紹介します。
「be_truthy」マッチャーは、引数に取ったオブジェクトが真であれば(「nil」または「false」でなければ)パスします。「be_falsey」マッチャーはその逆で「nil」または「false」であればパスします。
expect(borrowing.user) be_truthy
この例では「borrowing.user」が存在すればパスします。
RSpec 3より前のバージョンでは、それぞれ「be_true」「be_false」という名前でしたが、「true」や「false」と同一でなくてもパスできるため変更されました。同一かどうかを調べたいときは「be」マッチャーに「true」または「false」を渡します。
Rubyの演算子のマッチャーを以下に示します。
# books == [book] expect(books).to eq([book]) # books.size > 0 expect(books.size).to be > 0 # book.title =~ /Ruby/ expect(book.title).to match(/Ruby/)
「expect」はブロックを引数に取ることもできます。以下に例を示します。
expect { Book.create(name: 'test') }.to change{Book.count}.from(0).to(1)
このエクスペクテーションでは、「expect」のブロックを実行したとき、「change」マッチャーの方のブロックの値が「from」の引数から「to」の引数に変わることを期待しています。
RSpecの体系は巨大で、紹介しきれなかった仕組みがたくさんあります。以下に参考になるリンクについて紹介しておきます。
RSpecの公式ドキュメントです。
RSpecの良い書き方について日本語を含む多言語で紹介しています。
また受け入れテストのフレームワーク「Turnip」もRSpecベースで実装されています。ぜひ自身でも調べてみてください。
今回は、RSpecを例にRailsのテストについて解説しましたが、いかがでしたでしょうか。次回は、ActionMailerを使ったメール機能とActiveModelを使った永続化しないデータについて解説する予定ですので、お楽しみに。
林 慶(Rails技術者認定シルバー試験問題作成者)
平成2年大阪生まれ。2006年から高専で情報工学を学んでいたが当時は所謂プログラミングができない工学生だった。卒業後、高専の専攻科に上がったもののマンネリ化したキャンパスライフに飽きたため休学して渡豪。そこでプログラミングに対するコンプレックスを克服するためにRuby on Railsなどでアプリケーションを作ることを覚える。
帰国後から現在までは復学し推薦システムに関する研究を行いながら、アジャイルウェアでRuby on Railsアプリケーションの開発業務に従事している。
好きなメソッドはinject。
山根 剛司(Ruby業務開発歴7年)
兵庫県生まれ。1997年からベンチャー系のパッケージベンダーで10年間勤務。当時、使用していた言語はJavaとサーバーサイドJavaScript。
2007年よりITコンサル会社に転職し、Rubyと出会って衝撃を受ける。基幹システムをRuby on Railsで置き換えるプロジェクトに従事。それ以来Ruby一筋で、Ruby on Railsのプラグインやgemも開発。
2013年より、株式会社アジャイルウェアに所属。アジャイルな手法で、Ruby on Railsを使って企業向けシステムを構築する業務に従事。
Ruby関西所属。好きなメソッドはtap。
Twitter:@spring_kuma、Facebook:山根 剛司
Copyright © ITmedia, Inc. All Rights Reserved.