Пересмешивать все маршруты Rails в view_context - PullRequest
0 голосов
/ 13 марта 2019

Контроллер и представления Rails предоставляют view_context (обычно объект ActionView::Base), который предоставляет контекст для генерации представлений.

Обычным шаблоном является обтекание экземпляров модели в классе Presenter. В этом случае view_context обычно также передается в качестве аргумента, поэтому Presenter может вызывать методы представления (например, I8n.t(), помощники пути Rails и т. Д.). .) по мере необходимости.

В моих тестах RSpec я использую макет для проверки поведения view_context в Presenter. Специально для помощников по путям я должен смоделировать каждый путь по отдельности:

view_context = ActionView::Base.new
user = UserPresenter.new(FactoryBot.create(:user), view: view_context)

allow(view_context).to receive(:some_custom_path) do |opts|
  some_custom_path(opts)
end

Существует ли простой способ программным образом смоделировать все пути одновременно?

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

Спасибо!

РЕДАКТИРОВАТЬ: На самом деле приведенный выше фрагмент даже не правильно. Выдает ошибку, потому что view_context (ActionView::Base) даже не реализует :some_custom_path. Я предполагаю, что это мера защиты от того, чтобы заглушить то, что не существует.

1 Ответ

1 голос
/ 14 марта 2019

Почему вы хотите издеваться над всеми путями?

Полагаю, вас интересует на самом деле насмешка над этими звонками, а не просто заглушка. Смотрите разницу здесь .

Разные докладчики, вероятно, будут вызывать разные path методы для своих view_context. Я рекомендую явно высмеивать только те пути, которые вы ожидаете вызвать в тестируемом докладчике.

Вам не нужно издеваться над всеми путями, потому что не все они будут вызываться каждый раз.

Я бы написал ваш тест следующим образом:

describe UserPresenter do
  subject(:user_presenter) { described_class.new(user, view: view_context)

  let(:user) { FactoryBot.create(:user) }
  let(:view_context) { instance_double(ActionView::Base) }
  let(:some_custom_path) { 'some/custom/path' }

  before do
    allow(view_context).to receive(:some_custom_path).and_return(some_custom_path)
  end

  it 'does something'
end

Об ошибке, которую вы видите, да, instance_double защитит вас от использования метода, который не реализован на приемнике.

Я не рекомендую , вы делаете это, но если все, что вам нужно, это объект представления, который будет молча проглатывать вызовы path методов, тогда вы можете создать поддельный вид, подобный этому:

class FakeView
  private

  def view_methods
    ActionView::Base.instance_methods - Object.instance_methods
  end

  def method_missing(meth, *params, &block)
    view_methods.include?(meth) ? nil : super
  end
end

, а затем используйте его в своих тестах, например:

describe UserPresenter do
  subject(:user_presenter) { described_class.new(user, view: view_context)

  let(:user) { FactoryBot.create(:user) }
  let(:view_context) { FakeView.new }

  it 'does something'
end
...