1

我曾经用来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 匹配器调用 spaceship 运算符<=>来验证参数,所以它认为 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:

我该怎么做才能通过考试?

4

2 回答 2

2

发生这种情况是因为Comparableimplements ==,因此您的对象在以下方面被视为相等==

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
于 2021-10-12T11:45:48.823 回答
0

我的解决方案:使用匹配have_attributes准确检查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
于 2021-10-12T03:34:52.750 回答