我正在使用RSpec并且想要多次测试Singleton类的构造函数。
我该怎么做?
祝你好运
答案 0 :(得分:17)
Singleton类基本上就是这样做
def self.instance
@instance ||= new
end
private_class_method :new
因此,您可以通过使用send
调用private方法来完全绕过memoizationlet(:instance) { GlobalClass.send(:new) }
这种方式的一个好处是,由于测试运行,没有修改全局状态。
可能是一种更好的方式,来自this answer:
let(:instance) { Class.new(GlobalClass).instance }
这将创建一个继承自GlobalClass
的匿名类,所有类级实例变量都存储在该类中。然后在每次测试后抛弃它,使GlobalClass
保持不变。
答案 1 :(得分:7)
# singleton_spec.rb
require "singleton"
class Global
include Singleton
def initialize
puts "Initializing"
end
end
describe Global do
before do
Singleton.__init__(Global)
end
it "test1" do
Global.instance
end
it "test2" do
Global.instance
end
end
% rspec singleton_spec.rb -fd
Global
Initializing
test1
Initializing
test2
答案 2 :(得分:3)
查看http://blog.ardes.com/2006/12/11/testing-singletons-with-ruby:
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
答案 3 :(得分:3)
我见过的一种模式是让单身人士成为真正阶级的一个子类。您在生产代码中使用Singleton版本,但在测试时使用基础(非单例)类。
示例:
class MyClass
attr_accessor :some_state
def initialize
@some_state = {}
end
end
class MySingletonClass < MyClass
include Singleton
end
...但我正在寻找一种更好的方式。
我的部分问题是我正在使用JRuby并挂钩到Java系统首选项,其中 全局。其余我认为我可以重构。
答案 4 :(得分:2)
人们使用单身人士的一个原因是因为“全球变量很糟糕,不能吗?”单例是一个全局变量,在名称空间中隔离,并具有惰性实例化。考虑一个真正的全局变量是否可以简化事情,特别是如果你不需要延迟实例化。
答案 5 :(得分:1)
将其重构为可以多次构造的类。这具有从类中移除Singleton性质的副作用(有些人会说有益)。
以另一种方式看待它:你发现需要多次调用构造函数。为什么 该类只构造一个实例? Singleton提供什么好处?
答案 6 :(得分:0)
RSpec是否允许您执行预测试操作?是这样,您可以向静态类添加另一个方法,清除构造函数中完成的任何操作。然后在每次测试之前调用它。
答案 7 :(得分:-1)
您只需为每个规范创建一个新的it
并阻止。将您的规格细分为可测试单元。使用“之前”和“之后”来设置和清除您所做的任何事情。
before(:each)
块都会执行 after(:each)
和it
。