Ruby
RSpec

RSpec 3.4ではエラーが起きた行を出力結果に表示してくれるようになった

More than 3 years have passed since last update.


はじめに

2015年11月にRSpec 3.4がリリースされました。

派手は新機能はありませんが、実践的な機能改善が施され、テストのサイクルを効率よく回せるようになっています。

主な新機能についてはこちらの公式日本語訳(!)をご覧ください。

公式ブログには以下のような新機能が紹介されています。


  • Core: Bisect アルゴリズムの改善

  • Core: 失敗時の出力の改善


    • 複数行のコードスニペット

    • coderayがインストール済みの場合、シンタックスハイライトが有効に

    • 失敗元の行の検出の改善



  • Expectations: 複合エクスペクテーションの失敗時メッセージの改善

  • Expectations: match マッチャへの with_captures の追加

  • Rails: ActiveJob のための新しい have_enqueued_job マッチャ

この中で僕が一番注目したのが「 失敗元の行の検出の改善 」です。

ただ、残念なことにブログにはコードや出力結果の例が載っていなかったので、自分で実際に動かして確認してみました。

この記事ではその内容を紹介します。


テストコード

以下はContactクラスのnameメソッドをテストするテストコードです。

nameメソッドはfirstnameとlastnameを半角スペースで連結します。


spec/models/contact_spec.rb

describe Contact do

# ...

it "returns a contact's full name as a string" do
contact = build_stubbed(:contact,
firstname: 'Jane',
lastname: 'Smith'
)
expect(contact.name).to eq 'Jane Smith'
end

# ...
end



Contactクラスの実装

以下はContactクラスの実装です。

ただし、テストが失敗するようにわざと join の引数を半角スペースではなく 1 に変えています。


app/models/contact.rb

class Contact < ActiveRecord::Base

# ...

def name
# わざと join の引数を 1 に変えた
[firstname, lastname].join(1)
end

# ...
end



RSpec 3.3での実行結果

RSpec 3.3では "Failure/Error:" にテストが失敗したエクスペクテーション(expect(...).to ...)が表示されています。

Failures:

1) Contact returns a contact's full name as a string
Failure/Error: expect(contact.name).to eq 'Jane Smith'
TypeError:
no implicit conversion of Fixnum into String
# ./app/models/contact.rb:11:in `join'
# ./app/models/contact.rb:11:in `name'
# ./spec/models/contact_spec.rb:18:in `block (2 levels) in <top (required)>'
# ./spec/rails_helper.rb:40:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:39:in `block (2 levels) in <top (required)>'

Screen Shot 2015-11-15 at 15.21.30.png


RSpec 3.4での実行結果

RSpec 3.4では "Failure/Error:" にエラーが発生した行(Modelのコード)が表示されています。

Failures:

1) Contact returns a contact's full name as a string
Failure/Error: [firstname, lastname].join(1)

TypeError:
no implicit conversion of Fixnum into String
# ./app/models/contact.rb:11:in `join'
# ./app/models/contact.rb:11:in `name'
# ./spec/models/contact_spec.rb:18:in `block (2 levels) in <top (required)>'
# ./spec/rails_helper.rb:40:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:39:in `block (2 levels) in <top (required)>'

Screen Shot 2015-11-15 at 15.21.42.png


RSpec 3.4で失敗行を表示するルール

RSpec 3.3ではいつでもspecファイル(xxx_spec.rb)内で失敗した行を "Failure/Error:" として表示しています。

RSpec 3.4では config.project_source_dirs で定義されたディレクトリ内にあるコードが出力対象になります。

config.project_source_dirs のデフォルト値は ['spec', 'lib', 'app'] です。

上のサンプルコードでは app/models/contact.rb 内でエラーが起きたので、 "Failure/Error:" にModelのコードが表示されています。

Ruby本体やgemのコードは config.project_source_dirs に含まれないので、 "Failure/Error:" に表示されません。


まとめ

上のコードで示したように、RSpec 3.4ではRSpec 3.3に比べてエラーの発生箇所に近い場所を表示してくれるので、エラーの原因を特定しやすくなりました。

便利ですね!!


参考文献


RSpec 3.3についてはこちら

RSpec 3.3で導入された新機能についてはこちらにまとめてあります。

実用的な新機能が盛りだくさん!RSpec 3.3 完全ガイド - Qiita

「RSpec 3.4で改善されたBisectアルゴリズムって何?」と思ったりした人は上の記事を読んでみてください。


サンプルコードはEveryday Railsで使用しているコードです

サンプルコードは電子書籍「 Everyday Rails - RSpecによるRailsテスト入門 」で使用しているコードです。

RSpec初心者の方に最適な一冊ですので、よかったら読んでみてください。