为什么从ObjectSpace收集的连续数组在我的规范中不相同?

时间:2013-01-14 15:02:00

标签: ruby unit-testing garbage-collection rspec2 objectspace

我有一个带有两个与ObjectSpace相关的方法的Project类:

def self.all
  ObjectSpace.each_object(self).to_a
end

def self.count
  ObjectSpace.each_object(self).count
end

此规范失败:

it "can print all projects" do
  Project.all.should eq([@project1, @project2])
end

出现以下错误:

Failure/Error: Project.all.should eq([@project1, @project2])

       expected: [#<Project:0x007fd76a815508 @name="Building house", @tasks=[]>, #<Project:0x007fd76a815198 @name="Getting a loan from the Bank", @tasks=[]>]
            got: [#<Project:0x007fd7688336b8 @name="Building house", @tasks=[]>, #<Project:0x007fd7688dae40 @name="Building house", @tasks=[]>, #<Project:0x007fd768af4de8 @name="Getting a loan from the Bank", @tasks=[]>, #<Project:0x007fd768af5090 @name="Building house", @tasks=[]>, #<Project:0x007fd76a815198 @name="Getting a loan from the Bank", @tasks=[]>, #<Project:0x007fd76a815508 @name="Building house", @tasks=[]>]

正如你所看到的,这给了我一个数组加倍的对象,但代码本身工作正常。那么为什么我的测试失败了?

3 个答案:

答案 0 :(得分:2)

因为以前存在的Project仍然作为对象存在。

这意味着它们仍会在ObjectSpace中找到,并且您将拥有比预期更多的对象。

答案 1 :(得分:1)

ObjectSpace可能包含一些螺母痕迹

嗯,不是真的。但是ObjectSpace通常包含属于其他范围的对象,已标记为垃圾收集但尚未删除的对象,或者(特别是RSpec测试的情况下)来自前一个块的多个调用的对象副本。

Ruby 2.0可能有所不同,但早期的MRI解释器不保证垃圾收集,因此即使您手动运行{{3},也无法真正指望ObjectSpace的内容对于相等测试有效。 }。

重构您的代码

您可以考虑:

,而不是在规范中寻找相等性
  1. 寻找包含GC.start
  2. 的内容
  3. 在ObjectSpace中查找特定对象ID。
  4. 重构受测试的类以及测试本身。 具体来说,使用某种聚合模式而不是依赖ObjectSpace来保存对您关注的Project对象的引用。
  5. 你可以在这里混合搭配,但修复你的测试只是问题的一部分。底层应用程序逻辑似乎需要重构。

    失败的测试很好,因为它突出了需要手术的课程。不要只是修复测试;听听规范试图告诉你关于被测试课程的内容。

答案 2 :(得分:1)

<强> project_spec.rb

describe Project do

 let(:p1) { Project.new }
 let(:p2) { Project.new }

 describe ".all" do

  it "should keep track of all pr" do
   Project.all.should == [p1, p2]  
  end

 end

 describe ".count" do

  it "should count all the projects" do
   Project.count.should == 2
  end

 end

end

<强> project.rb

class Project

  @@all_projects = []

  def initialize(options=nil)
    @@all_projects << self
  end

  def self.all
    @@all_projects
  end

  def self.count
    @@all_projects.count
  end

end


Finished in 0.00079 seconds
2 examples, 0 failures

我会告诉你,你可以找出可能对你的项目特别复杂的其他细节。希望这对你有用。