😏

【Rspec】例外発生の後のインスタンスの状態を調べたい時の対処法

2023/02/24に公開

概要

あるサービスクラスで例外発生した際にサービスクラスの外で例外を拾うような実装だった場合に、
そのサービスクラス内のインスタンスの状態をどうやってテストすればいいかわからなかったので、調べてみた。

なにがしたいの?

例えば、仮に以下のようなサービスクラスがあったとする。(この実装が好ましいかどうかは今回は無視する)

sample.rb
class NameService
    def initialize(user, company)
      @user = user
      @company = company
    end

    def execute
      ActiveRecord::Base.transaction do
        @user.update!(name: "テストユーザ")
        @company.update!(name: "テスト会社")
      end    
    end
 end

company.update!で例外を発生した場合に、ロールバックしたことを確かめるべく、@userの状態をテストした場合どうしたらいいいのだろうか。

パッとおもついた感じにすると以下のような感じ?

sample_spec.rb
      before do
        allow_any_instance_of(Company).to \
	  receive(:update!).and_raise(StandardError)
        NameService.new(user, company).execute 
      end
      
      it '更新されていないこと' do
          expect(user.reload.name).not_to eq "テストユーザ"
      end

でもこれではうまくいかない。
なぜなら、そもそもこのサービスクラスで例外が発生しているので、単体テストにおいては正常に終了しない。
下記のようなエラーが出てくる。

ターミナル
     Failure/Error: @company.update!(name: "テスト会社")
     
     StandardError:
       StandardError

どうしたらいい?

色々調べてみたが、下記のようにspecファイル内で例外を受け取るようにするのが手っ取り早い。

      it '更新されていないこと' do
        begin
          NameService.new(user, company).execute 
        rescue
          expect(user.reload.name).not_to eq "テストユーザ"
        end
      end

まとめ

今回は、ゴリ押しで例外発生後にどうやってRspecテストするかをまとめてみました。
本当は、こういうことせずに網羅的にテストできるように設計すること強く推奨します。

Discussion