Ruby+;Rspec+;OpenStruct异常行为

Ruby+;Rspec+;OpenStruct异常行为,ruby,rspec,rspec3,Ruby,Rspec,Rspec3,所以我在测试ruby类时遇到了这种奇怪的行为。顺便说一句,我正在用RSpec3来测试它 类Foo有一个“fetch_object”方法,它从类栏调用“find”方法来检索对象,然后从获取的对象调用方法“fail” 当我希望收到方法“fail”一次而没有收到时,就会出现所谓的奇怪行为,但如果我将方法名称更改为“faill”,它就像一个符咒:S 以下是戏剧: require 'ostruct' class Foo def fetch_object foobar = Bar.find

所以我在测试ruby类时遇到了这种奇怪的行为。顺便说一句,我正在用RSpec3来测试它

类Foo有一个“fetch_object”方法,它从类栏调用“find”方法来检索对象,然后从获取的对象调用方法“fail”

当我希望收到方法“fail”一次而没有收到时,就会出现所谓的奇怪行为,但如果我将方法名称更改为“faill”,它就像一个符咒:S

以下是戏剧:

require 'ostruct'

class Foo

  def fetch_object
    foobar = Bar.find
    foobar.fail
  end

end

class Bar

  def self.find
    OpenStruct.new(name: 'Foo Bar')
  end

end

describe Foo do

  subject { Foo.new }

  let(:foo) { OpenStruct.new() }

  before do
    expect(Bar).to receive(:find).and_return(foo)
  end

  it 'fetch object with name' do
    expect(foo).to receive(:fail)
    subject.fetch_object
  end

end

我怀疑这是因为您正在对对象设置一个期望值,该对象的行为取决于
方法\u missing
OpenStruct

出于这个原因,我不希望将其作为模拟,我将使用常规模拟(规范将通过):

您正在这里进行测试,如果返回的对象(Bar.find的结果)将收到预期的消息,而不涉及实现细节

对诸如ostruct之类的动态类设置期望值可能会导致奇怪的结果。似乎在某个时刻调用了
Kernel#fail
方法,因此,将名称更改为
faill
或任何其他尚未被内核“接受”的名称将使其工作

另一个解决方案是monkeypatching OpenStruct,以避免
方法\u丢失
调用:

class OpenStruct
  def fail
    true
  end
end

class Foo

  def fetch_object
    foobar = Bar.find
    foobar.fail
  end

end

class Bar

  def self.find
    OpenStruct.new(name: 'Foo Bar')
  end

end

describe Foo do

  subject { Foo.new }

  let(:foo) { OpenStruct.new }

  before do
    expect(Bar).to receive(:find).and_return(foo)
  end

  it 'fetch object with name' do
    expect(foo).to receive(:fail)
    subject.fetch_object
  end

end
但我不知道你为什么要这么做;)


更多信息:

当我运行您的代码时,我得到了
失败/错误:expect(Bar)。接收(:find)。和返回(foo)()。查找(任何参数)预期:接收任何参数1次:接收任何参数0次
class OpenStruct
  def fail
    true
  end
end

class Foo

  def fetch_object
    foobar = Bar.find
    foobar.fail
  end

end

class Bar

  def self.find
    OpenStruct.new(name: 'Foo Bar')
  end

end

describe Foo do

  subject { Foo.new }

  let(:foo) { OpenStruct.new }

  before do
    expect(Bar).to receive(:find).and_return(foo)
  end

  it 'fetch object with name' do
    expect(foo).to receive(:fail)
    subject.fetch_object
  end

end