例外が起きたあとのテストに関してあまり情報がなく、事例もなかったので
広く皆様の意見を聞きたい意図も含めて記事に起こしました。
TL;DR
エラー(正確にはStandardError)が発生する機能に関して、エラー発生後の状態をテストしたいがエラーが発生した時点でRSpecが止まってしまう。
そのため、例外の内容をチェックしないのであれば、rescueしたあとに本来やりたい作業を行うのが一番無難な回避策
実コードを交えてた問題点の解説
テスト対象とするサンプルクラス
今回は以下のサンプルクラスに対してのrspecとして例を書いて行きます。
class Calculate
def initialize
# わかりやすい初期値をいれる
@result = -9999
end
# 10を引数で割る
def ten_division(number)
@result = 10 / number
@result
end
def last_result
@result
end
end
やりたいこと
ten_division
の引数に0を指定した場合に last_result
の戻り値 は初期値の -9999
であることを確認したい。
発生する問題点
何も考えずにそのまま書くと以下のようなコード
context "0を指定した場合" do
let(:obj) { Calculate.new }
it "last_resultで-9999が戻ってくる" do
obj.ten_division(0)
expect(obj.last_result).to eq(-9999)
end
end
ただこの場合、Exceptionがあがって途中でspecが止まってしまう。
1) 0を指定した場合 last_resultで-9999が戻ってくる
Failure/Error: @result = 10 / number
ZeroDivisionError:
divided by 0
このため後続の expect(obj.last_result).to eq(-9999)
が実行されずにエラーでRSpecが終了してしまう
回避案
エラーが起きるアクションに関してrescueして、その後期待される要素の取得をして確認をする。
コードで表すと以下の通り
context "0を指定した場合" do
let(:obj) { Calculate.new }
it "last_resultで-9999が戻ってくる" do
begin
obj.ten_division(0)
rescue
end
expect(obj.last_result).to eq(-9999)
end
end
一応ワンライナーでも書ける
context "0を指定した場合" do
let(:obj) { Calculate.new }
it "last_resultで-9999が戻ってくる" do
obj.ten_division(0) rescue
expect(obj.last_result).to eq(-9999)
end
end
各種関連リンク
サンプルコード
exception後の挙動を確かめるRSpec
※ 本ページでは紹介していない、errorそのもののテストに関しても記載しています。
参考サイト
- RSpec での例外処理について
- RSpecでexpectとraise_errorを使ったときのエラー - Qiita
- Rubyで独自例外を定義するときはStandardErrorを継承する - Hack Your Design!
編集後記
一応この記事を書いた経緯的なものは以下に。
Errorが起きた後の状態を調べるrspecの書き方が全然見当たらないので書いた - コード日進月歩