Можно ли использовать рубиновые уточнения для изменения поведения действия контроллера в тестах?
Можно ли использовать функцию уточнений, чтобы заглушить действие контроллера?
Я определяю уточнение в "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
не используйте методы уточнения из-за лексической области видимости. Это не использует ваш конкретный вариант использования (действия контроллера), но это та же концепция, и показывает, что уточнения оказываются трудными для использования таким образом.