Ruby 为什么从ObjectSpace收集的连续数组在我的规范中不相等?
我有一个带有两个ObjectSpace相关方法的项目类:Ruby 为什么从ObjectSpace收集的连续数组在我的规范中不相等?,ruby,unit-testing,garbage-collection,rspec2,objectspace,Ruby,Unit Testing,Garbage Collection,Rspec2,Objectspace,我有一个带有两个ObjectSpace相关方法的项目类: 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/E
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=[]>]
失败/错误:Project.all.should eq([@project1,@project2])
预期值:[#,#]
得到:[#、#、#、#、#、#、#、#、#]
正如您所看到的,这将使我的数组中的对象加倍,但代码本身运行良好。那么为什么我的测试失败了呢?因为以前存在的
项目仍然作为对象存在
这意味着它们仍然可以在ObjectSpace
中找到,并且您将拥有比预期更多的对象。因为以前存在的项目仍然作为对象存在
这意味着它们仍然可以在ObjectSpace
中找到,并且您将拥有比预期更多的对象。ObjectSpace可能包含坚果的痕迹
嗯,不是真的。但是ObjectSpace通常包含属于其他作用域的对象、已标记为垃圾收集但尚未删除的对象,或者(特别是在RSpec测试的情况下)来自before块多次调用的对象副本
Ruby 2.0可能有所不同,但早期的MRI解释器不能保证垃圾收集,因此即使手动运行,也不能指望ObjectSpace的内容对相等性测试有效
重构你的代码
与其在规范中寻找平等性,不如考虑:
寻找包含
在ObjectSpace中查找特定的对象ID
重构被测试的类以及测试本身具体来说,使用某种聚合模式,而不是依赖ObjectSpace来保存对您关心的项目对象的引用。
您可以在这里混合搭配,但修复测试实际上只是问题的一部分。底层应用程序逻辑似乎需要重构
失败的测试是好的,因为它突出了一个需要手术的班级。不要只是修改测试;请听一下规范试图告诉您的关于被测试类的内容。ObjectSpace可能包含一些坚果的痕迹
嗯,不是真的。但是ObjectSpace通常包含属于其他作用域的对象、已标记为垃圾收集但尚未删除的对象,或者(特别是在RSpec测试的情况下)来自before块多次调用的对象副本
Ruby 2.0可能有所不同,但早期的MRI解释器不能保证垃圾收集,因此即使手动运行,也不能指望ObjectSpace的内容对相等性测试有效
重构你的代码
与其在规范中寻找平等性,不如考虑:
寻找包含
在ObjectSpace中查找特定的对象ID
重构被测试的类以及测试本身具体来说,使用某种聚合模式,而不是依赖ObjectSpace来保存对您关心的项目对象的引用。
您可以在这里混合搭配,但修复测试实际上只是问题的一部分。底层应用程序逻辑似乎需要重构
失败的测试是好的,因为它突出了一个需要手术的班级。不要只是修改测试;听听规范试图告诉您的关于被测试类的内容。project\u 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
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
project.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
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
类项目
@@所有_项目=[]
def初始化(选项=nil)
@@所有项目项目规范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
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
project.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
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
类项目
@@所有_项目=[]
def初始化(选项=nil)
@@所有的项目啊-你是对的。那么,解决这个问题的正确方法是什么?我应该在上下文之后销毁吗?我该怎么做?@AmitErandole我不确定;你可以从一开始。或者,您可以坚持使用原始解决方案并保留一个引用列表,但在每个规范末尾删除它们。不过,对不起,我不确定最好的主意是什么。嗯,所以我猜使用ObjectSpace是不可能的-这真的是这里要学的课程吗?我想知道…@AmitErandole-您可以在项目
类上定义一个终结器
,当您执行ObjectSpace.garbage\u collect
时将调用它。但是实现实际上是由一个事实驱动的——你是需要通过你的规范,还是需要实现对上下文严格要求?我想这两者都需要。但我现在想知道的是,我是否应该首先使用ObjectSpace
。让我看看如何使用定稿器啊-你说得对。那么,解决这个问题的正确方法是什么?我应该在上下文之后销毁吗?我该怎么做?@AmitErandole我不确定;你可以从一开始。或者,您可以坚持使用原始解决方案并保留一个引用列表,但在每个规范末尾删除它们。不过,对不起,我不确定最好的主意是什么。嗯,所以我猜使用ObjectSpace是不可能的-这真的是这里要学的课程吗?我想知道…@AmitErandole-您可以在项目
类上定义一个终结器
,当您执行ObjectSpace.garbage\u collect
时将调用它。但是实现实际上是由一个事实驱动的——你是需要通过你的规范,还是需要实现对上下文严格要求?我想这两者都需要。但我现在想知道的是,我是否应该首先使用ObjectSpace
。让我看看如何使用定稿人,为什么这个问题仅仅因为为了简洁而被编辑就被否决了?你最初提出的问题是一道“代码墙”,很可能会被关闭为“过于本地化”。提出好的问题需要将你的问题浓缩到本质,并确保该问题也与将军未来的来访者相关