如何在Ruby中重置一个单例对象?我知道在真实的的代码中永远不会有人想这样做,但是单元测试呢?
下面是我在RSpec测试中尝试做的事情-
describe MySingleton, "#not_initialised" do
it "raises an exception" do
expect {MySingleton.get_something}.to raise_error(RuntimeError)
end
end
它失败了,因为我之前的一个测试初始化了Singleton对象。我试过遵循Ian白色在this链接中的建议,该链接本质上是猴子补丁Singleton提供reset_instance方法,但我得到了一个未定义的方法'reset_instance'异常。
require 'singleton'
class <<Singleton
def included_with_reset(klass)
included_without_reset(klass)
class <<klass
def reset_instance
Singleton.send :__init__, self
self
end
end
end
alias_method :included_without_reset, :included
alias_method :included, :included_with_reset
end
describe MySingleton, "#not_initialised" do
it "raises an exception" do
MySingleton.reset_instance
expect {MySingleton.get_something}.to raise_error(RuntimeError)
end
end
在Ruby中实现这一点最惯用的方法是什么?
3条答案
按热度按时间quhf5bfb1#
一个坚韧的问题是,单例是粗糙的,部分原因是你正在展示(如何重置它),部分原因是他们做出的假设有可能在以后咬你(例如大多数Rails)。
有几件事你可以做,他们都是“好”在最好的。最好的解决方案是找到一种方法来摆脱单例。这是手波浪,我知道,因为没有一个公式或算法,你可以应用,它消除了很多方便,但如果你能做到这一点,它往往是值得的。
如果你做不到,至少尝试注入单例而不是直接访问它。现在测试可能很难,但是想象一下在运行时必须处理这样的问题。为此,你需要内置的基础设施来处理它。
以下是我想到的六种方法。
提供类的示例,但允许类被示例化。这是最符合传统的单例呈现方式的。基本上任何时候你想引用单例,你都可以和单例示例对话,但你可以对其他示例进行测试。在stdlib中有一个模块可以帮助做到这一点,但它使
.new
成为私有的。所以如果你想使用它,你必须使用像let(:config) { Configuration.send :new }
这样的东西来测试它。然后,在您想要访问它的任何地方,使用
Configuration.instance
使单例成为某个其他类的示例。这样你就可以隔离地测试其他类,而不需要显式地测试你的单例。
然后在您的应用程序某处:
您可以确保永远不编辑主类,然后只需为您的测试子类化它:
然后在您的应用程序某处:
确保有一种方法可以重置单例。或者更一般地说,撤销你所做的任何事情。(例如,如果你可以向单例注册某个对象,那么你需要能够取消注册它,在Rails中,例如,当你子类化
Railtie
时,它会将其记录在数组中,但你可以access the array and delete the item from it)。克隆类而不是直接测试。这是我做的一个要点,基本上你编辑克隆而不是真实的的类。
在模块中开发行为,然后将其扩展到单例。Here是一个稍微复杂的例子。如果需要初始化对象上的一些变量,可能你必须研究
self.included
和self.extended
方法。然后在您的应用程序某处:
wz3gfoph2#
我想简单地这样做就可以解决你的问题:
或者更好地在回调之前添加:
yhqotfr83#
如果你以前有这个
不如这样做