【问题标题】:Test Rails model with several initializations with Rspec使用 Rspec 进行多次初始化测试 Rails 模型
【发布时间】:2014-03-26 16:32:45
【问题描述】:

我正在为 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 技巧,但即使它被替换,它在 :participant 关联中的引用类也不会发生同样的情况

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

【问题讨论】:

    标签: ruby-on-rails ruby rspec metaprogramming


    【解决方案1】:

    我不明白你为什么要使用如此困难的方式来创建和销毁对象(通过 :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
    

    【讨论】:

    • 嗨,我知道undefine class 是唯一一种困难的方法,而且效果很好。无论如何,我将编辑我的问题以使其更清楚。关于puts,它只是一个调试打印,你可能是说LimesurveyRails::SurveyParticipation.reflect_on_association(:participant).. 我要编辑这个,但我知道我的LimesurveyRails::SurveyParticipation 类只有一个关联
    • 嗨,可能是关联缓存问题 (guides.rubyonrails.org/v2.3.11/…) 尝试使用 true 选项丢弃关联的缓存副本:LimesurveyRails::SurveyParticipant(true ).object_id == self.object_id
    • 感谢您的关注,但您提到的是关于类实例而不是类。还有一个错误/错别字..你不能在一个类上调用参与者(true)..它是一个返回实例的实例方法。我使用 object_id 来找出关联中使用了什么类
    • 这是我的荣幸。可能我不太明白这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    相关资源
    最近更新 更多