Ruby + Rspec + OpenStruct странное поведение

Так что я испытываю это странное поведение во время тестирования рубинового класса. Я использую rspec 3, чтобы проверить это, кстати.

Класс Foo имеет метод fetch_object, который вызывает метод find из класса Bar для извлечения объекта, а затем вызывает метод 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

1 ответ

Я подозреваю, что это потому, что вы устанавливаете ожидание для объекта, поведение которого зависит method_missing (OpenStruct).

По этой причине я бы не хотел использовать его как макет, я бы использовал обычный макет (и спецификация пройдет):

let(:foo) { double('foobar') }

Вы тестируете здесь, если возвращаемый объект (результат Bar.find) получит ожидаемое сообщение, не вдаваясь в детали реализации.

Установка ожиданий для динамических классов, таких как ostruct, может привести к странным результатам. Кажется, что в какой-то момент Kernel#fail метод вызывается, таким образом, изменяя имя на faill или любой другой, который еще не "взят" ядром, заставит его работать.

Другим решением будет использование OpenStruct, чтобы избежать method_missing быть названным:

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

Но я не знаю, почему вы хотите это сделать;)

Дополнительная информация: Двойники и динамический класс

Другие вопросы по тегам