RSpec any_instance return self - программирование

RSpec any_instance return self

Я пытаюсь заглушить любой экземпляр некоторого класса. Мне нужно заглушить метод fetch, который заполняет "я" некоторыми данными.

Как получить доступ к переменной self, изменить ее и вернуться к методу fetch?

MyObject.any_instance.stub(:fetch) { self }

не возвращает экземпляр MyObject.

Возможно, в этой ситуации более полезны издевательства. К сожалению, я еще не понял их.

4b9b3361

Ответ 1

Там открыть проблему rspec-mocks, чтобы решить эту проблему. Надеюсь, что в какой-то момент я попытаюсь обратиться к нему, но не просто добавить это так, чтобы не нарушать существующие спецификации, которые используют any_instance с реализацией блока, потому что мы начнем давать дополнительный аргумент (например, экземпляр объекта).

В целом, any_instance может пригодиться в некоторых ситуациях, но это немного запах, и у вас, как правило, будет меньше проблем, если вы сможете найти способ издеваться или заглушить отдельные экземпляры.

Вот работа, которую я не тестировал, но должен работать:

orig_new = MyObject.method(:new)
MyObject.stub(:new) do |*args, &block|
  orig_new.call(*args, &block).tap do |instance|
    instance.stub(:fetch) { instance }
  end
end

По существу, мы моделируем any_instance здесь, подключаясь к MyObject.new, чтобы мы могли заглушить fetch для каждого нового экземпляра, который был создан.

Все, что было сказано, важно "слушать ваши тесты", и, когда что-то трудно проверить, подумайте о том, что говорится о вашем дизайне, а не сразу используйте электроинструменты, такие как any_instance. Ваш оригинальный вопрос не дает мне достаточного контекста, чтобы я мог что-то рассказать о вашем дизайне, но определенно, где бы я начал, когда сталкивался с необходимостью сделать это.

Ответ 2

Насколько я вижу, это почему-то кажется невозможным. Я проверил текущую реализацию rspec-mocks, и метод, фактически вызывающий реализацию заглушки, выглядит следующим образом:

# lib/rspec/mocks/message_expectation.rb:450
def call_implementation(*args, &block)
    @implementation.arity == 0 ? @implementation.call(&block) : @implementation.call(*args, &block)
end

Как кажется, блок просто вызывается сам по себе, а не через instance_eval. Возможно, есть еще одна техника для достижения того, чего вы хотите, ведь я вообще не специалист RSpec.