Techioz Blog

rspec - ActiveRecord::RecordNotFound をテストする方法

概要

人々の属性を更新するメソッドがあり、人々が見つからない場合に ActiveRecord::RecordNotFound を救出します。方法は次のとおりです。

  def update
    @people= People.find(params[:id])
    if @people.update(people_params)
      render json: { success: 'Success' }
    else
      render :edit
    end
  rescue ActiveRecord::RecordNotFound => e
    render json: { error: 'Failed') }
  end

そして、レコードが見つからないときの状況をテストしたいと思います。今のところのテストは次のとおりです。

    let(:people) { create(:people) }
    let(:people_id) { people.id }
    let(:user) { people}
    # Other tests...
    context 'when person not found' do
      let(:exception) { ActiveRecord::RecordNotFound }

      # What should I write so that I can let the record not been found?

      before { allow(People).to receive(:find).and_raise(exception) }

      it 'responds with json containing the error message' do
        expect(JSON.parse(response.body)).to eq({error:'Error'})
      end
    end

レコードが見つからない条件でテストを実行したいと考えています。でもどうすればいいのか分かりません。 let(people) {nil} を設定しようとしましたが、機能しませんでした。とにかくそれを行う方法はありますか?ありがとう!

解決策

これはそもそも良い解決策ではありません。 Rails では、コントローラー レベルで一般的なエラーを処理するために、rescue_from を使用したいと考えています。

class ApplicationController
  rescue_from ActiveRecord::RecordNotFound, with: :not_found

  def not_found
    respond_to do |format|
      format.json { head :404 }
    end
  end
end

これにより、継承を使用してコードを DRY できるようになります。

render json: { error: 'Failed') }

アンチパターンです。リクエストが失敗した場合は、正しい HTTP ステータス コードを送信してクライアントに通知する必要があります。

コントローラーが不足しているリソースを正しく処理するかどうかをテストしたい場合は、次のようにします。

let(:people) { create(:people) }
let(:people_id) { people.id }
let(:user) { people}

it "returns the correct response code if the person cannot be found" do
  get '/people/notarealid'
  expect(response).to have_http_status :not_found
end

これはスタブを使用せず、実装を実際にテストします。