简体   繁体   中英

Test Rails model with several initializations with Rspec

I am writing Rspec test for a Ruby On Rails engine. My engine provide ActiveRecord models with a class method is_a_limesurvey_participant(opts = {}) that extends them with class variables and associations. To test my TestModel extension I need to initialize it multiple times in different and consecutive RSpec contexts providing different options. To do so I need to undefine my TestModel otherwise it will "remember" old settings. I do that calling the following utility method before test inspired by this :

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

And that's ok.

Here's the problem. My engine has a model (SurveyParticipation) which need to be related to my main app TestModel with an association. I do this in my is_a_limesurvey_participant method this way:

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

I expected the puts call to always show me true for any examples each time my TestModel call is_a_limesurvey_participant method because LimesurveyRails::SurveyParticipation.reflect_on_association(:participant).klass should be the current TestModel and so it is if I run my test separately.

But running my tests all together show me that LimesurveyRails::SurveyParticipation.reflect_on_association(:participant).klass references always the same TestModel object, that is, the one which was the current one the first time Rspec ran is_a_limesurvey_participant method.

If I try to retrieve both objects by object_id I can see that they both exist in the 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)

I also tried to do the same reset_test_model trick for LimesurveyRails::SurveyParticipation class but even if it gets replaced, the same doesn't happen for its referenced class in the :participant association

In few words belongs_to, after the first call, retrieve the first/wrong/cancelled/unreferenced TestModel. Apart from this situation what is a good pattern to test different class configurations with Rspec? Of course running the test separately makes all working fine, is this the right pattern?

I can not understand why are you use such difficult way for create and destroy objects (via :remove_const and file load). Ruby has a garbage collector so just create objects with TestModel.new.is_a_limesurvey_participant(opts = {different_options}) and do not worry about destroy them.

As for puts and that it should always print true: I think that array of all reflected associations (reflect_on_all_associations) for LimesurveyRails::SurveyParticipation won't always return first element for current object.

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

When you run individual tests, then array of associations (after rails load into memory) has only one element and reflect_on_all_associations.first works fine. But for each next test, the first element won't be actual.

One possible solution, may be, is try to change reflect_on_all_associations to reflect_on_association

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM