0

I'm using Ruby 2.2.1 and Rails 4.2.0

I'm adding test cases to cover a module. The module basically runs some QA checks on data pulled in from another system. The problem I'm having is that across test cases, an iteration inside the module is re-using the same object instead of the individual objects for the individual test cases.

Sample test cases:

...

it "should add issue case 1" do
  trip = FactoryGirl.build(:trip, :case_1)
  p trip.object_id # 7...8660
  subject.do_qa(trip)
  expect(trip.issue_1).not_to be_nil
end

it "should add issue case 2" do
  trip = FactoryGirl.build(:trip, :case_2)
  p trip.object_id # 7...2780
  subject.do_qa(trip)
  expect(trip.issue_2).not_to be_nil
end

...

Sample module:

module Qa

  ...

  def self.do_qa(trips)
    p trips.object_id # Same is the object id in the calling test case
    @trips ||= Array.wrap(trips)
    @trips.each do |t|
      p t.object_id # Always the object id from the first test case!
      ... # Checks for case 1 and case 2
    end
  end

  ...

end

Because the loop is re-using the object, the second test case never passes because the module is just re-evaluating the first trip object. Is there a way to force it to instantiate a new object in the loop??

Chris Patten
  • 129
  • 3
  • 13
  • There is an awful way, and there might be a nicer way, but we'd need to see more code. What other methods in `Qa` refer to `@trips`? What class includes `Qa`? What is `subject` in your tests? ([RSpec's subject is mostly a bad thing.](http://stackoverflow.com/questions/38437162/whats-the-difference-between-rspecs-subject-and-let-when-should-they-be-used)) – Dave Schweisguth Aug 03 '16 at 13:22

1 Answers1

0

The answer to this ended up being my lack of full understanding of Ruby vs. other languages. Basically, even though a Module isn't defined as a class, it's still a class behind the scenes and the instance variables stay set between runs. This hasn't been an issue in my application because nothing has relied on them being cleared out between method calls.

Case 1 and Case 2 in the original question are actually using the same instance of the Qa class, so of course the instance variable is going to still contain the original trip object since I was using the ||= operator.

I resolved it by adding a before(:each) block to the beginning of the relevant context with Qa.instance_variable_set(:@trips, []) to ensure that the variable is starting in a clean state.

Chris Patten
  • 129
  • 3
  • 13
  • Yeah, or you could do proper OOP and not store data in global state. Meaning, actually instantiate a `Qa` class and work with an __instance__, not the __class__. – Sergio Tulentsev Aug 09 '16 at 17:41