Как мне преобразовать функцию «continue_any_instance_of ()» (как это устарело), ​​чтобы мои тесты rspec на уровне носителя все еще проходили? - PullRequest
1 голос
/ 08 ноября 2019

Из документации rspec expect_any_instance_of() устарело. Однако я пока не нашел простого способа заменить этот метод другим. Все, что я пробовал до сих пор, терпит неудачу, и особенно, вызывается метод, который, как ожидается, будет смоделирован.

context 'test Foo' do
  before(:each) do
    info = double(
      size: 12345,
      close: true
    )
    allow(Blah).to receive(:open).and_return(info)  # this one works
  end                                                                       

  it 'returns false on failure' do
    # This expect_any_instance_of() works like a charm
    expect_any_instance_of(MyUploader).to receive(:process_with_some_tool).and_return(false)

    uploader = MyUploader.new(create(:my_object, data: nil))

    # These expect()'s fails
    expect(MyUploader).to receive(:process_with_some_tool).and_return(true)
    expect(uploader).to receive(:process_with_some_tool).and_return(true)

    uploader.store!(trigger_data)
  end
end

Первый expect(MyUploader) (то же самое с именем класса), я также пытался поместить внутрьблок before. Я как бы ожидал, что он все равно потерпит неудачу, так как имя класса объекта uploader выглядит следующим образом (и, конечно, число меняется при каждом запуске):

MyUploader::Uploader47181996911040

Однако я неЯ не понимаю, почему expect(uploader) (то есть с объектом, который я только что выделил) тоже не работает. Поскольку я привязан к самому созданному мною объекту, почему бы ему не высмеять это событие :process_with_some_tool и просто вернуть true?

У меня есть puts "CALLED\n" в моем :process_with_some_tool, и яувидеть это сообщение, когда я использую expect(). Я не вижу его, когда использую expect_any_instance_of(). Так что первый ничего не высмеивает, а второй насмехается, как и ожидалось ...

Я также попытался обернуть голову вокруг справочной страницы Method , но, опять же, я несмог заставить его работать.

Итак, мой вопрос: как мы можем преобразовать expect_any_instance_of(), чтобы он действительно работал?

Примечание: я новичок в Ruby, Rails, RSpec и все такое. Я подозреваю, что это легко, но я просто не понимаю, как заставить все это работать ...


Реализация проприетарна, но вот базовое представление того, что я использую:

class MyUploader < CarrierWave::Uploader::Base
  include Inspectable

  version :cleanup do
    process :func1
    process :func2
    process :func3
    after :store, :check_size
  end

  def func1
    # Do work
  end

  def func2
    if info.close
      tmpfile = 'temp_file1.ext'
      successful_processing = process_with_some_tool1(tmpfile)
      log "message 1" unless successful_processing
    end

    if !info.close
      tmpfile = 'temp_file2.ext'
      successful_processing = process_with_some_tool2(tmpfile)
      log "message 2" unless successful_processing
    end
  end

  def func3
    # Do work
  end

  def process_with_some_tool1(tmpfile)
    puts "TOOL1 RUN"
    system %Q{mytool1 -a -b -c "#{tmpfile}"}
  end

  def process_with_some_tool2(tmpfile)
    puts "TOOL2 RUN"
    system %Q{mytool2 -a -b -c "#{tmpfile}"}
  end

  def check_size
    begin
      if size < 100
        raise "Too small"
      end
    rescue => error
      log "some message"
    end
  end
end

Это базовое представление о том, что у меня есть. Код является частным, поэтому я не могу просто скопировать и вставить все это.

Я вижу сообщение "TOOL2 RUN", когда я ожидаю, что один (и tool1) будет заглушкой из-за expect().

Обратите внимание, что я не вижу, чтобы store был реализован здесь. Итак, оно исходит из базового класса.


Обновление:

Я вижу, что store!() вызывает cache(), и это вызывает versions!(), а реализация versions!() включаетследующая функция инициализации:

    def build_version(name, options)                                        
      uploader = Class.new(self)                                            
      const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)   
      uploader.version_names += [name]                                      
      ...snip...
    end

Как мы видим, эта функция создает новый класс и называет его «Uploader <#id>», что я и вижу, когда я печатаю class / object_id в консоль.

Проверяя все идентификаторы, теперь я вижу, что реальный объект, использованный в тесте, - это тот, который создан Class.new(), а не тот, который я создаю в своем коде.

This build_version метод происходит от ~/.rvm/gems/ruby-2.5.3/gems/carrierwave-0.11.0/lib/carrierwave/uploader/versions.rb. Это часть функции загрузчика, которая кэширует файлы для ваших тестов. Похоже, что он не ограничивается кэшированием файлов, хотя ... Теперь мне интересно, получу ли я доступ к этому кешированному объекту, и мне будет позволено вместо этого присоединить мой expect() или allow() к этой версии. Я специально уточню у Carrierwave реализации 1066 *. Скорее всего, у них будет решение этой проблемы.

...