gpt4 book ai didi

ruby - 在 RSpec 中 stub /模拟全局常量

转载 作者:数据小太阳 更新时间:2023-10-29 07:12:19 25 4
gpt4 key购买 nike

我有一个 gem,它有一个根据 Rails.env 的不同行为的方法:

def self.env
if defined?(Rails)
Rails.env
elsif ...

现在我想编写一个规范来测试这个代码路径。目前我是这样做的:

Kernel.const_set(:Rails, nil)
Rails.should_receive(:env).and_return('production')
...

没关系,只是感觉很丑。另一种方法是在 spec_helper 中声明:

module Rails; end

而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:

rails = double('Rails')
rails.should_receive(:env).and_return('production')

但是,好吧,事实并非如此。还是我做错了什么?

最佳答案

根据关于此的各种推文,打开常量通常是一个坏主意,因为它使测试变得有点挑战,并且您必须更改常量的状态才能这样做(这使它们不太稳定)。也就是说,如果您编写的插件必须根据加载环境的不同而表现不同,那么您将不得不测试 RailsMerb< 是否存在 等到某个地方,即使它不在代码的这个特定部分。无论它在哪里,您都希望将其隔离,以便决策只发生一次。类似于 MyPlugin::env。现在您可以在大多数地方安全地 stub 该方法,然后通过 stub 常量来指定该方法。

至于如何 stub 常量,你的例子看起来不太正确。代码询问是否 defined?(Rails),但是 Kernel.const_set(:Rails, nil) 并没有取消常量的定义,它只是将它的值设置为 。你想要的是这样的东西(免责声明 - 这是我的头脑,未经测试,甚至没有运行,可能包含语法错误,并且没有很好地分解):

def without_const(const)
if Object.const_defined?(const)
begin
@const = const
Object.send(:remove_const, const)
yield
ensure
Object.const_set(const, @const)
end
else
yield
end
end

def with_stub_const(const, value)
if Object.const_defined?(const)
begin
@const = const
Object.const_set(const, value)
yield
ensure
Object.const_set(const, @const)
end
else
begin
Object.const_set(const, value)
yield
ensure
Object.send(:remove_const, const)
end
end
end

describe "..." do
it "does x if Rails is defined" do
rails = double('Rails', :env => {:stuff_i => 'need'})
with_stub_const(:Rails, rails) do
# ...
end
end

it "does y if Rails is not defined" do
without_const(:Rails) do
# ....
end
end
end

我会考虑是否应该将其包含在 rspec 中。这是其中之一,如果我们添加人们会在他们不需要时将其用作依赖常量的借口:)

关于ruby - 在 RSpec 中 stub /模拟全局常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7847982/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com