Ruby 如何测试单例类?

Ruby 如何测试单例类?,ruby,singleton,rspec,testing,Ruby,Singleton,Rspec,Testing,我正在使用RSpec,希望不止一次地测试一个单例类的构造函数 我该怎么做 向您致意RSpec是否允许您执行测试前操作?因此,您可以向静态类添加另一个方法,该方法清除了构造函数中所做的任何操作。然后在每次测试之前调用它。将它重构为一个可以多次构造的类。这样做的副作用(有些人会说是有益的)是从类中删除单例特性 换一种方式来看:您发现需要多次调用构造函数。为什么类只能构造一个实例?Singleton提供了什么好处?您可以简单地为每个规范创建一个新的并阻塞。将您的规范分解为一个可测试的单元。使用“之前”

我正在使用RSpec,希望不止一次地测试一个单例类的构造函数

我该怎么做


向您致意

RSpec是否允许您执行测试前操作?因此,您可以向静态类添加另一个方法,该方法清除了构造函数中所做的任何操作。然后在每次测试之前调用它。

将它重构为一个可以多次构造的类。这样做的副作用(有些人会说是有益的)是从类中删除单例特性


换一种方式来看:您发现需要多次调用构造函数。为什么类只能构造一个实例?Singleton提供了什么好处?

您可以简单地为每个规范创建一个新的
并阻塞。将您的规范分解为一个可测试的单元。使用“之前”和“之后”设置并清除您所做的任何事情

在(:each)
之前和(:each)
之后对每个
块执行

查看:

require'singleton'

类人们使用单例的一个原因是“全局变量不好,m'kay?”单例是一个全局变量,被隔离在名称空间中,并且具有延迟实例化。考虑一个真正的全局变量是否可以简化事情,特别是如果你不需要懒惰实例化的时候。

< P> >我看到的一个模式是让单体成为真实类的子类。在生产代码中使用单例版本,但在测试中使用基本(非单例)类

例如:

class MyClass
  attr_accessor :some_state

  def initialize
     @some_state = {}
  end
end

class MySingletonClass < MyClass
  include Singleton
end
class-MyClass
属性访问器:某些状态
def初始化
@某些状态={}
结束
结束
类MySingletonClass
……但我自己也在寻找更好的方法


我的问题的一部分是,我正在使用JRuby并与Java系统首选项挂钩,这是全局的。剩下的我想我可以重构出来。

单例类基本上就是这样做的

# 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
def self.instance
  @instance ||= new
end

private_class_method :new
因此,通过使用send调用私有方法new,可以完全绕过备忘录

let(:instance) { GlobalClass.send(:new) }
这种方法的一个很好的好处是,运行测试时不会修改全局状态


可能是更好的方法,来自:


这将创建一个匿名类,该类继承自
GlobalClass
,所有类级实例变量都存储在该类中。然后在每次测试后将其丢弃,保持
GlobalClass
不变。

RSpec有“before”和“after”块。但是由于Singleton模式,构造函数不会被调用两次。构造函数不需要被调用多次,但我希望保持规范清晰-因此我在每个规范中只测试构造函数的一部分。关键是“Singleton.\uu init\uuu(Global)”。这对我来说很重要。谢谢。问题是,这会重置单身。如果您的应用程序的任何其他部分依赖于先前设置的全局状态,则会中断。例如,如果您正在使用注册表模式,那么如何在不中断对使用注册表的组件的测试的情况下测试注册表?这是一个简单、直接的解决方案。谢谢,这非常有用。谢谢!这应该是正确的答案。问题是,在测试运行时,全局状态会被修改。请参阅下面我的答案,以获得更清晰的方法。
let(:instance) { GlobalClass.send(:new) }
let(:instance) { Class.new(GlobalClass).instance }