Могу ли я переопределить метод в RSpec только для одного вызова аргумента

У меня есть механизм включения функций в нескольких проектах (один с использованием RSpec 1 с Rails 2 и один с RSpec 2 / Rails 3), и я ищу лучший способ переопределить только одну функцию без необходимости делать что-нибудь с другими функциями. В конечном итоге я ищу способ заглушить метод, когда он вызывается с определенным аргументом, и вести себя нормально в противном случае.

Закрывать:

Project::Config.should_receive(:feature_enabled?).with('new_feature').any_number_of_times.and_return(true)
get :index # calls feature_enabled? for a few other features too

>> <Project::Config (class)> expected feature_enabled? with 'new_feature' but received it with 'some old feature'

Работает, но я ищу что-то более чистое, особенно в тех случаях, когда может быть несколько блоков before {} на разных уровнях, позволяющих использовать разные функции.

Project::Config.should_receive(:feature_enabled?).with('new_feature').any_number_of_times.and_return(true)
# expect any other calls
Project::Config.should_receive(:feature_enabled?).any_number_of_times
# I can't override any features here.  This is annoying if I try to set up expectations at a few different levels
get :index # might call feature_enabled? for a few features

Это также не удается:

Project::Config.stub(:feature_enabled?).with('new_feature').and_return(true)
get :index

>> undefined method `feature_enabled?' for Project::Config:Class

В идеале я мог бы сделать что-то в одной строке, что не влияет на другие feature_enabled? звонки. Если есть что-то, что просто работает для RSpec2, это нормально, поскольку мы в какой-то момент обновим другой проект.


person Alex Dixon    schedule 23.03.2012    source источник


Ответы (2)


Лучшее решение, которое я нашел для вызова исходного метода, работает следующим образом:

method = Project::Config.method(:feature_enabled?)

Project::Config.stub(:feature_enabled?).and_return do |arg|
  method.call(arg)
end

Project::Config.should_receive(:feature_enabled?).with('new_feature').and_return(true)
person Daniel Evans    schedule 26.04.2012
comment
Замечательно - мне нужно сохранять небольшое дополнительное состояние во время каждого запуска, чтобы отслеживать несколько функций, которые переопределяются, но это работает идеально. Спасибо, Даниэль! - person Alex Dixon; 27.04.2012
comment
Без проблем. Я всегда ищу способы исправить это, но, увы, пока не нашел ничего лучше. - person Daniel Evans; 28.04.2012

Вот, возможно, немного более чистая альтернатива, доступная в RSpec 3:

allow(Project::Config).to receive(:feature_enabled?).and_wrap_original do |method, arg|
  case arg
  when 'new_feature'
    true
  else
    method.call(arg)
  end
end

Если вы знаете, что вам нужен только один случай, вы также можете использовать троичный или даже простой ||:

allow(Project::Config).to receive(:feature_enabled?).and_wrap_original do |method, arg|
  arg == 'new_feature' || method.call(arg)
end
person lobati    schedule 20.09.2019