Techioz Blog

InstanceDouble(session) (anonymous)> 予期しないメッセージを受信しました:[]=

概要

rspec の動作に問題があります。セッションを使用するサービスのテストを作成して、値を読み取り、この値を上書きしようとしています。

たとえば、テストしたいこと

class CurrentCartService
  attr_reader :user, :session

  def initialize(user, session)
    @user = user
    @session = session
  end

  def cart_id
    { id: session[:cart_id] }
  end

  def assigne_cart_to_session
    session[:cart_id] = current_cart.id
  end

スペック

describe CurrentCartService do
  let(:current_user) { user }
  let(:session) { double('session') }

  let!(:cart) { create(:cart) }

  subject { described_class.new current_user, session }

  before do
    allow(session).to receive(:[]).and_return(cart.id)
  end

  describe '#call' do
    context 'when user is not signed' do
      let(:user) { nil }
      it { subject.call }
    end
  end
end

バインディング.こじ開け

session[:cart_id]
=> 574
session[:cart_id] = 123
RSpec::Mocks::MockExpectationError: #<InstanceDouble(session) (anonymous)> received unexpected message :[]= with (:cart_id, 123)

これを修正するにはどうすればよいですか?期待して書いてみた

expect(session).to receive(:[])

しかし、それは機能しません、それはまだ同じエラーです

解決策

このメッセージは、あなたのダブルが引数:cart_id と 123 を持つメッセージ []= を受信したが、それを予期していなかったということを示しています。

いくつかの基本的なロジックを適用してみましょう。問題は:

したがって、メッセージを取り除くためにできることは 2 つあります。

最初の方法は簡単です。session[:cart_id] = current_cart.id と書かれている 14 行目を削除するだけです。これは、[]= を呼び出している唯一の場所だからです。しかし、それはあなたがやりたいことではないと思います。

2番も簡単です。特定のメッセージを期待するように double に指示できる Expect と呼ばれるメソッドがあります。したがって、私たちがしなければならないのは、期待を設定することだけです。

適切な失敗メッセージはテスト フレームワークにおいて非常に重要であり、ありがたいことに RSpec には適切な失敗メッセージがあります。失敗メッセージには、テストを進める方法が示されます。引用したメッセージには、必要な情報がすべて含まれています。

何も考えずに、文字通りこの情報をコピー&ペーストするだけです。

expect(session).to receive(:[]=).with(:cart_id, 123)

あるいは、テストの脆弱性を少し減らし、123 をハードコーディングしないようにしたい場合は、次のようなこともできます。

expect(session).to receive(:[]=).with(:cart_id, instance_of(Integer))