RSpec: 如何通过对象标识比较 have_received 个参数?
RSpec: How to compare have_received arguments by object identity?
我曾经使用 expect(subject/double).to haved_received(:a_method).with(args).exactly(n).times
来测试一个方法是否被调用了一些特定的参数并且被调用了 {n} 次。但是今天它打破了参数是 Comparable
个对象,看看下面的代码:
设置
class A; end
class B
include Comparable
attr_reader :val
def initialize(val)
@val = val
end
def <=>(other)
self.val <=> other.val
end
end
class S
def call(x); end
end
s = S.new
allow(s).to receive(:call)
现在下面的测试通过了普通对象 A
a1 = A.new
a2 = A.new
s.call(a1)
s.call(a2)
expect(s).to have_received(:call).with(a1).exactly(1).times
expect(s).to have_received(:call).with(a2).exactly(1).times
但它因 Comparable
对象 B
而失败
b1 = B.new(0)
b2 = B.new(0)
s.call(b1)
s.call(b2)
expect(s).to have_received(:call).with(b1).exactly(1).times
expect(s).to have_received(:call).with(b2).exactly(1).times
我调试看到rspec匹配器调用宇宙飞船运算符<=>
来验证参数,所以它认为b1和b2是相同的
Failure/Error: expect(s).to have_received(:call).with(b1).exactly(1).times
expected: 1 time with arguments:
received: 2 times with arguments:
我应该怎么做才能通过考试?
我的解决方案:使用 the have_attributes
matcher 来准确检查对象参数的 object_id
expect(s).to have_received(:call).with(have_attributes(object_id: b1.object_id))
.exactly(1).times
expect(s).to have_received(:call).with(have_attributes(object_id: b2.object_id))
.exactly(1).times
发生这种情况是因为 Comparable
实现了 ==
,因此您的对象在 ==
:
方面被视为相等
b1 = B.new(0)
b2 = B.new(0)
b1 == b2 #=> true
要根据对象标识设置约束,您可以使用 equal
匹配器:(或其别名 an_object_equal_to
/ equal_to
)
expect(s).to have_received(:call).with(an_object_equal_to(b1)).once
在幕后,这个匹配器调用 equal?
:
b1 = B.new(0)
b2 = B.new(0)
b1.equal?(b2) #=> false
我曾经使用 expect(subject/double).to haved_received(:a_method).with(args).exactly(n).times
来测试一个方法是否被调用了一些特定的参数并且被调用了 {n} 次。但是今天它打破了参数是 Comparable
个对象,看看下面的代码:
设置
class A; end
class B
include Comparable
attr_reader :val
def initialize(val)
@val = val
end
def <=>(other)
self.val <=> other.val
end
end
class S
def call(x); end
end
s = S.new
allow(s).to receive(:call)
现在下面的测试通过了普通对象 A
a1 = A.new
a2 = A.new
s.call(a1)
s.call(a2)
expect(s).to have_received(:call).with(a1).exactly(1).times
expect(s).to have_received(:call).with(a2).exactly(1).times
但它因 Comparable
对象 B
b1 = B.new(0)
b2 = B.new(0)
s.call(b1)
s.call(b2)
expect(s).to have_received(:call).with(b1).exactly(1).times
expect(s).to have_received(:call).with(b2).exactly(1).times
我调试看到rspec匹配器调用宇宙飞船运算符<=>
来验证参数,所以它认为b1和b2是相同的
Failure/Error: expect(s).to have_received(:call).with(b1).exactly(1).times
expected: 1 time with arguments:
received: 2 times with arguments:
我应该怎么做才能通过考试?
我的解决方案:使用 the have_attributes
matcher 来准确检查对象参数的 object_id
expect(s).to have_received(:call).with(have_attributes(object_id: b1.object_id))
.exactly(1).times
expect(s).to have_received(:call).with(have_attributes(object_id: b2.object_id))
.exactly(1).times
发生这种情况是因为 Comparable
实现了 ==
,因此您的对象在 ==
:
b1 = B.new(0)
b2 = B.new(0)
b1 == b2 #=> true
要根据对象标识设置约束,您可以使用 equal
匹配器:(或其别名 an_object_equal_to
/ equal_to
)
expect(s).to have_received(:call).with(an_object_equal_to(b1)).once
在幕后,这个匹配器调用 equal?
:
b1 = B.new(0)
b2 = B.new(0)
b1.equal?(b2) #=> false