InstanceDouble(session) (匿名)> 收到意外消息 :[]= with

dam*_*anw 5 ruby rspec ruby-on-rails ruby-on-rails-5

我对 rspec 行为有疑问。我尝试为我使用的服务编写测试session,以读取一些值并覆盖该值。

例如我想测试什么

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

Run Code Online (Sandbox Code Playgroud)

spec

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
Run Code Online (Sandbox Code Playgroud)

binding.pry

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

如何解决这个问题?我尝试写一些expect

expect(session).to receive(:[])
Run Code Online (Sandbox Code Playgroud)

但还是不行,还是同样的错误

Jör*_*tag 6

该消息告诉您,您的替身收到了[]=带有参数的消息:cart_id123但没有预料到。

让我们应用一些基本逻辑。问题是:

  1. 收到消息
  2. 这是没有预料到的

因此,您可以采取两件事来消除该消息:

  1. 不发送消息或
  2. 告诉分身等待消息

第一个很简单:只需删除第 14 行,其中显示“ session[:cart_id] = current_cart.idsince that is the only place you are Calling” []=。但是,我认为这不是您想要做的。

第二点也很容易。有一个名为的方法expect可以让你告诉替身期待某个消息。所以,我们需要做的就是建立一个期望。

良好的失败消息在测试框架中非常重要,值得庆幸的是,RSpec确实有良好的失败消息。失败消息应该告诉您如何继续进行测试,并且您引用的消息包含我们需要的所有信息:

  • 引发失败的双精度名称 ( session)
  • 导致失败的意外消息的名称 ( []=)
  • 甚至是传递给消息的参数 (:cart_id123)

我们所要做的就是,不假思索,直接复制并粘贴以下信息:

expect(session).to receive(:[]=).with(:cart_id, 123)
Run Code Online (Sandbox Code Playgroud)

或者,如果我们希望我们的测试不那么脆弱并且不对 进行硬编码123,我们也可以这样做:

expect(session).to receive(:[]=).with(:cart_id, instance_of(Integer))
Run Code Online (Sandbox Code Playgroud)