如何在 case 语句中 stub\mock 实例?

How to stub\mock instance in case statement?

我有一个 class 方法,它使用另一个 class 实例方法:

class Foo
  def foo
    # a lot of code here, which return String instance
  end
end

class Bar
  class UnknownType < StandardError;end 

  def initialize(foo)
    self.foo = foo
  end 

  attr_reader :foo 

  def call
    # some code which use method foo
    foo
  end

  private

  def foo=(attr)
    @foo ||= case attr
               when Foo then attr.foo
               when String then attr
               else raise UnknownType, "Unknown type #{attr.class.name}"
             end
  end

end

而且我的测试不起作用,我尝试子方法: - is_a - kind_of?

let(:foo) { instance_double(Foo, foo: 'some text') }
let(:bar) { Bar.new(foo) }

subject { bar.call }

it 'make some business logic here' do
  expect { subject }.to be_truthy
end

但它引发错误 UnknownType 因为模板是 #<InstanceDouble(Foo) (anonymous)>

不是 Foo

instance_double(Foo).class != Foo。如您所见,returns 一个 InstanceDouble 对象不能用于您的比较目的。

我会用手动实例化和存根替换你的 instance_double 行:

let(:foo) do
  foo = Foo.new
  allow(foo).to receive(:foo).and_return "some text"
  foo
end
let(:bar) { Bar.new(foo) }

这样 foo.class == Foo 它会在你的案例陈述中正常工作。

Case 语句使用 === 来实现大小写相等的目的,在这种情况下 Foo 是接收者而不是参数。例如

  case attr
    when Foo then attr.foo
  end 

attrFoo 进行比较,因为 Foo === attr 而不是相反。

因此您可以将测试更改为

it 'make some business logic here' do
  allow(Foo).to receive(:===).with(foo).and_return(true)
  expect { subject }.to be_truthy
end

这样,当它评估您的 case 语句时,它将遵循 when Foo 路径,因为 Foo === attr 由于存根而为真。