Можно ли использовать рубиновые уточнения для изменения поведения действия контроллера в тестах?

Можно ли использовать функцию уточнений, чтобы заглушить действие контроллера?

Я определяю уточнение в "my_controller_refinement.rb"

require "my_controller"

module MyControllerRefinement
  refine MyController do
    def create_item(my_object = {})
      return "test_id"
    end
  end
end

И используя его в тесте следующим образом -

require_relative "my_controller_refinement"

class MyControllerTest < ActionController::TestCase
  using MyControllerRefinement

  test "get item" do
    post :create { my_object: { name: "Test", id: "test_id" } }
    # Post redirects to the show page
    assert_redirected_to action: "show", id: "test_id"
  end
end

Тестовый каталог как -

test/
  -->  my_controller_refinement.rb
  -->  my_controller_test.rb

Но доработка не срабатывает, и кажется, что вызывается фактическое действие контроллера.

Я что-то упустил или не могут быть использованы уточнения для такой "заглушки"?

2 ответа

Это не сработает из-за того, как в настоящее время работают уточнения. Документы (цитируемые ниже) имеют полный объем, но по сути область применения уточнения очень узка.

Вы можете активировать уточнения только на верхнем уровне, а не внутри какого-либо класса, модуля или метода. Вы можете активировать уточнения в строке, передаваемой в Kernel # eval, которая оценивается на верхнем уровне. Уточнения активны до конца файла или до конца строки eval, соответственно.

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

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

class OrigClass
  def test_method
    # checks if some methods are defined and calls them if they are
    puts (!! defined? patch_method_1) && patch_method_1
    puts (!! defined? patch_method_2) && patch_method_2
  end
  # the refinement will attempt to overwrite this method
  def patch_method_1; 0; end
end

puts OrigClass.new.test_method # => 0 false

module Refinement
  refine OrigClass do
    # this method is already defined on OrigClass
    def patch_method_1; 1; end
    # this one is not
    def patch_method_2; 2; end
  end
end

# re-open the class to add the refinement
class OrigClass
  using Refinement
  puts new.test_method # => 0 false
  puts new.patch_method_1 # => 1
  puts new.patch_method_2 # => 2
end

puts OrigClass.new.test_method # => 0 false

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

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