使用Rspec进行多次初始化的测试Rails模型

时间:2014-03-26 16:32:45

标签: ruby-on-rails ruby rspec metaprogramming

我正在为Ruby On Rails引擎编写Rspec测试。我的引擎为ActiveRecord模型提供了一个类方法is_a_limesurvey_participant(opts = {}),它使用类变量和关联扩展它们。要测试我的TestModel扩展,我需要在不同的连续RSpec上下文中多次初始化它,提供不同的选项。为此,我需要取消定义我的TestModel,否则它将会记住"旧的设置。我之前在this启发测试之前调用以下实用程序方法:

def reset_test_model
  Object.send(:remove_const,'TestModel')
  load File.join(ENGINE_RAILS_ROOT,'spec','dummy','app','models','test_model.rb')
end

那没关系。

这就是问题所在。我的引擎有一个模型(SurveyParticipation),需要与我的主应用程序TestModel相关联。我这样在我的is_a_limesurvey_participant方法中这样做:

def is_a_limesurvey_participant(opts = {})

  # ... class variables definitions

  has_many :survey_participations, :class_name => "LimesurveyRails::SurveyParticipation", :foreign_key => "participant_id"

  LimesurveyRails::SurveyParticipation.belongs_to :participant, :class_name => self.name, :foreign_key => 'participant_id' 

  puts (LimesurveyRails::SurveyParticipation.reflect_on_association(:participant).klass.object_id == self.object_id)

end

我希望每次我的TestModel调用is_a_limesurvey_participant方法时,puts调用始终显示任何示例,因为LimesurveyRails :: SurveyParticipation.reflect_on_association(:participant).klass应该是当前的TestModel,所以如果我运行我的测试分别。

但是一起运行我的测试表明,LimesurveyRails :: SurveyParticipation.reflect_on_association(:participant).klass始终引用相同的TestModel对象,即Rspec第一次运行is_a_limesurvey_participant方法时的当前对象。

如果我尝试通过object_id检索这两个对象,我可以看到它们都存在于ObjectSpace中:

(rdb:1) ObjectSpace._id2ref(70222826866840)
TestModel(id: integer, name: string, surname: string, email_address: string, extra_id: string, created_at: datetime, updated_at: datetime)
(rdb:1) ObjectSpace._id2ref(70222827277420)
TestModel(id: integer, name: string, surname: string, email_address: string, extra_id: string, created_at: datetime, updated_at: datetime)

我还尝试为LimesurveyRails :: SurveyParticipation类执行相同的reset_test_model技巧,但即使它被替换,在参与者关联中引用的类也不会发生同样的事情

在很少的话中,belongs_to,在第一次调用之后,检索第一个/错误/已取消/未引用的TestModel。除了这种情况,使用Rspec测试不同类配置的好模式是什么?当然,单独运行测试可以使所有工作正常,这是正确的模式吗?

1 个答案:

答案 0 :(得分:0)

我无法理解为什么你使用这种困难的方式创建和销毁对象(通过:remove_const和文件加载)。 Ruby有一个垃圾收集器,所以只需使用TestModel.new.is_a_limesurvey_participant(opts = {different_options})创建对象,不要担心会破坏它们。

至于 puts 并且它应该始终打印为true:我认为 LimesurveyRails :: SurveyParticipation 的所有反映关联(reflect_on_all_associations)的数组总是不会返回当前对象的第一个元素。

LimesurveyRails::SurveyParticipation.reflect_on_all_associations.first.klass.object_id

当你运行单独的测试时,那么关联数组(在rails加载到内存之后)只有一个元素而reflect_on_all_associations.first工作正常。但是对于每个下一个测试,第一个元素都不会是实际的。

可能的一种解决方法是尝试将reflect_on_all_associations更改为reflect_on_association

 reflect_on_all_associations.first.klass.object_id 
 -->
 reflect_on_association(:belongs_to).klass.object_id