我必须测试一些在Ruby3.2中提供大量 meta编程工具的基类。棘手的部分是,它基于另一个类的常量名称创建方法和工具。这在生产和开发中很好,因为Zeitwerk会自动加载所有依赖项:当缺少MyBaseTooling
时,它会查找一个名为my_base_tooling.rb
的文件并为我加载该类。
然而,在RSpec中,我必须自己使用stub_const
来处理它:
before do
stub_const(MyBaseTooling, Class.new(Tooling::Base))
stub_const(MyClass, Class.new(described_class) do
setup(MyBaseTooling) # parses the name "MyBaseTooling" and does some logic based on the name
end)
end
当你有一些上下文块并且你覆盖了更深的块中的定义时,这个get非常混乱,非常快:
describe do
let(:my_base_tooling) do
stub_const(MyBaseTooling, Class.new(Tooling::Base))
end
let(:my_class) do
my_base_tooling # preload the constant
stub_const(MyClass, Class.new(described_class) do
setup(MyBaseTooling) # parses the name "MyBaseTooling" and does some logic based on the name
end)
end
context "with more logic in my base tooling" do
let(:my_base_tooling) do
stub_const(MyBaseTooling, Class.new(Tooling::Base) do
# more custom logic
end)
end
end
end
我不喜欢的部分是通过在let(:my_class)
中调用my_base_tooling
的let来手动加载MyBaseTooling
。想象一下,你不仅仅有2个类,你有8个或更多的类(这是我目前的情况)。
所以我想,也许我可以为RSpec提供一个自定义的查找逻辑,当一个常量丢失时,就像Zeitwerk一样。但我不是查找文件,而是查找具有相同命名约定的let帮助程序。到目前为止,我的想法是:
- 使用
const_missing
(https://devdocs.io/ruby~3.2/module#method-i-const_missing) - 当一个常量丢失时,执行一个
name.underscore
,并查看是否用这个名称定义了一个let;如果是,则返回此值
我玩了const_missing
钩子,但到目前为止还没有任何运气。有什么想法可以做到这一点,或者这是否可能?
1条答案
按热度按时间5anewei61#
看看你的测试代码,我认为你需要做的就是使用
let!
,像这样:通常,RSpec会延迟加载
let
语句。换句话说,它会一直等待,直到您引用let
定义的常量,以执行与let
语句关联的代码块。通过将bang(
!
)添加到let
语句中,您告诉RSpec立即执行块中的代码。这具有立即将值赋给变量的效果。这样,就不再需要在my_class
let语句中调用my_base_tooling
。MyBaseTooling
将已被存根化。请注意,我在
my_base_tooling
的两个定义上都调用了let!
。您需要这样做,否则当调用my_class
时,第一个定义将出现,但context
中的第二个定义将不存在。