如何测试Singleton类?

时间:2009-12-15 17:51:24

标签: ruby singleton rspec testing

我正在使用RSpec并且想要多次测试Singleton类的构造函数。

我该怎么做?

祝你好运

8 个答案:

答案 0 :(得分:17)

Singleton类基本上就是这样做

def self.instance
  @instance ||= new
end

private_class_method :new

因此,您可以通过使用send

调用private方法来完全绕过memoization
let(: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