RSpec で例外テストの書き方、および ActiveRecord の例外をテストする際の注意

スポンサーリンク

昨日のエントリー、Rails モデルの RSpec 単体テストで validation と DB に対するテストを区別した | EasyRamble の補足エントリーになります。

【お知らせ】 英単語を画像イメージで楽に暗記できる辞書サイトを作りました。英語学習中の方は、ぜひご利用ください!
画像付き英語辞書 Imagict | 英単語をイメージで暗記
【開発記録】
英単語を画像イメージで暗記できる英語辞書サービスを作って公開しました
スポンサーリンク

— 環境 —
rails-4.0.1
rspec-rails-2.14.0
capybara-2.2.0

RSpec で例外をテストするコード

unique キー制約の付いていてるDBカラムに対して、以下のように例外の発生を確認するテストを書いたのですが、この時はまった箇所がありました。

spec/models/user_spec.rb

User モデルについて、email カラムが DB で unique 制約となっています。なので、既存のユーザーと email が同一のユーザーを保存しようとしたら、例外(ActiveRecord::RecordNotUnique)が発生することを意図して書いたテストコードです。このテストコードは、正しく動作します。

save と save! は違う

【追記 2014/12/08】
Rails勉強中さんにコメントを頂きまして、このパラグラフの記述が間違っていることに気付きましたので訂正します。save メソッドでも ActiveRecord::RecordNotUnique は raise され、save メソッドでは ActiveRecord::RecordInvalid のエラーだけが rescue されて false を返しているとのことです。なので、この記事内の ActiveRecord::RecordNotUnique の例外捕捉のテストでは、save! ではなく save を使っても構いません。Rails のソースコードを確認したところ、確かにそうなっていました。

save (ActiveRecord::Persistence) – APIdock

以降このパラグラフの間違えていた文章は、打ち消し線で訂正しておきます。Rails勉強中さん、ご指摘ありがとうございました!
【追記ここまで】

の行についてなのですが、最初以下のように書いていました。

save メソッドは、レコード保存に失敗しても false を返すだけです。なので、何の例外も発生させず、以下のようにテストを通らず。

レコード保存の失敗時に例外を返すためには、感嘆符付きの save! メソッドを使う必要があります。

validation のスキップには validate: false

上記コードを書いてテストを行ってみましたところ、次のエラー。

User モデルに書いてある validation に引っかかってしまい、DB に保存するところまで行ってません。なので、validation を無効にする必要がある。

ということで、最終的に以下のように変更。

これで、意図した通りに、ActiveRecord::RecordNotUnique を発生させるテストを実行できました。

スポンサーリンク
私は Rails のテストフレームワークには RSpec を使っています。サーバーのテスト用に Serverspec もおすすめです。
 
スポンサーリンク
  • 2件のコメント
  • Rails勉強中

    saveでもActiveRecord::RecordNotUniqueはraiseされますよん。

    saveメソッドがrescueでfalse返しているのは、ActiveRecord::RecordInvalidのエラーだけなので。

    データベースエラーやBugなのでraiseされた場合は、rescueされまえん

    • taka

      Rails勉強中さん、ご指摘ありがとうございます。訂正いたしました。

Leave Your Message!