Если вы проверите документацию для #class_eval
(например, https://ruby -doc.org / core-2.5.0 / Module.html # method-i-class_eval ), вы увидите ответьте там: «Оценивает строку или блок в контексте мода, , за исключением того, что когда задан блок, поиск константы / переменной класса не затрагивается ».
Таким образом, включение в class_eval
просто не влияет на разрешение констант.
Насколько я понимаю из краткого обзора исходного кода minitest, describe
внутренне создает новый анонимный класс (назовем его C
) и помещает в него class_eval с предоставленным вами блоком. Во время этого вызова it
s создайте соответствующие методы экземпляра теста, которые будут выполнены позже. Но include
не влияет на разрешение констант для C
, поэтому Bar
остается неизвестным.
Существует очевидное (и довольно некрасивое) решение - должно работать следующее, потому что вы включаете Foo
во внешний контекст, поэтому Bar переходит в лексическую область, доступную для describe
:
include Foo
describe Foo do
it "foos" do
do_stuff
Bar.new
end
end
Но я бы избежал такого кода. Возможно, лучше установить макет класса явно, что-то вроде
module Foo
def do_stuff
"foo"
end
class Bar
def do_stuff
"bar"
end
end
end
...
describe Foo do
let(:cls) { Class.new }
before { cls.include(Foo) }
it "foos" do
assert cls.new.do_stuff == "foo"
end
it "bars" do
assert cls::Bar.new.do_stuff == "bar"
end
end
(но возьмите, пожалуйста, последний с крошкой соли - я почти никогда не использую Minitest, поэтому понятия не имею о его "общих идиомах")