InstanceDouble(session)(匿名)> 收到意外消息:[]= with
InstanceDouble(session) (anonymous)> received unexpected message :[]= with
我对 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
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
binding.pry
session[:cart_id]
=> 574
session[:cart_id] = 123
RSpec::Mocks::MockExpectationError: #<InstanceDouble(session) (anonymous)> received unexpected message :[]= with (:cart_id, 123)
如何解决这个问题?我试着写了一些 expect
expect(session).to receive(:[])
但是还是不行,还是一样的错误
该消息告诉您,您的替身收到消息 []=
,参数为 :cart_id
和 123
,但没有预料到。
让我们应用一些基本逻辑。问题是:
- 收到消息
- 这出乎意料
因此,您可以通过两种方式删除该消息:
- 不发送消息或
- 告诉分身期待消息
第一个很简单:只需删除第 14 行 session[:cart_id] = current_cart.id
,因为这是您调用 []=
的唯一地方。但是,我认为这不是你想要做的。
第二条也很简单。有一种叫做 expect
的方法可以让你告诉替身等待某个消息。所以,我们需要做的就是建立一个期望。
好的失败消息在测试框架中非常重要,值得庆幸的是,RSpec确实有好的失败消息。失败消息应该告诉您如何继续进行测试,您引用的消息包含我们需要的所有信息:
- 引发失败的替身名称 (
session
)
- 导致失败的意外消息的名称 (
[]=
)
- 甚至传递给消息的参数(
:cart_id
和 123
)
我们所要做的就是,想都不想,直接复制粘贴这些信息:
expect(session).to receive(:[]=).with(:cart_id, 123)
或者,如果我们希望我们的测试不那么脆弱而不是硬编码 123
,我们也可以这样做:
expect(session).to receive(:[]=).with(:cart_id, instance_of(Integer))
我对 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
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
binding.pry
session[:cart_id]
=> 574
session[:cart_id] = 123
RSpec::Mocks::MockExpectationError: #<InstanceDouble(session) (anonymous)> received unexpected message :[]= with (:cart_id, 123)
如何解决这个问题?我试着写了一些 expect
expect(session).to receive(:[])
但是还是不行,还是一样的错误
该消息告诉您,您的替身收到消息 []=
,参数为 :cart_id
和 123
,但没有预料到。
让我们应用一些基本逻辑。问题是:
- 收到消息
- 这出乎意料
因此,您可以通过两种方式删除该消息:
- 不发送消息或
- 告诉分身期待消息
第一个很简单:只需删除第 14 行 session[:cart_id] = current_cart.id
,因为这是您调用 []=
的唯一地方。但是,我认为这不是你想要做的。
第二条也很简单。有一种叫做 expect
的方法可以让你告诉替身等待某个消息。所以,我们需要做的就是建立一个期望。
好的失败消息在测试框架中非常重要,值得庆幸的是,RSpec确实有好的失败消息。失败消息应该告诉您如何继续进行测试,您引用的消息包含我们需要的所有信息:
- 引发失败的替身名称 (
session
) - 导致失败的意外消息的名称 (
[]=
) - 甚至传递给消息的参数(
:cart_id
和123
)
我们所要做的就是,想都不想,直接复制粘贴这些信息:
expect(session).to receive(:[]=).with(:cart_id, 123)
或者,如果我们希望我们的测试不那么脆弱而不是硬编码 123
,我们也可以这样做:
expect(session).to receive(:[]=).with(:cart_id, instance_of(Integer))