如何在case语句中存根\模拟实例?

时间:2019-04-30 19:30:59

标签: ruby rspec

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

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

2 个答案:

答案 0 :(得分:1)

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由于存根而为true。

答案 1 :(得分:0)

instance_double(Foo).class != Foo。如您所见,这将返回一个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语句中正常工作。