I am attempting to refactor the tests in the amoeba gem (
https://github.com/amoeba-rb/amoeba) with a view to being able to fix some
bugs and (possibly) add new features.

The tests require ActiveRecord models with associations (has_one, has_many,
etc) and for the existing tests these are defined all together in one place
for the whole suite but, for me, this makes it hard to understand what
features are tested in each unit test. I would therefore like to create
temporary models with each test, and I can do that as follows:

```
# Create the tables in the database
ActiveRecord::Base.connection.drop_table :parents, if_exists: true
ActiveRecord::Base.connection.drop_table :children, if_exists: true
ActiveRecord::Base.connection.create_table :parents
ActiveRecord::Base.connection.create_table :children do |t|
  t.references :parent
end

# Stub models (so that they are discarded after the tests)
stub_const 'Parent', Class.new(ActiveRecord::Base)
stub_const 'Child', Class.new(ActiveRecord::Base)

# Configure the models, as required
Parent.class_eval 'has_one :child'
```

This works OK but I have a problem if I try to use the same temporary model
names with a different association type. Here is an example:

```
require 'spec_helper'

RSpec.describe 'testing' do
  before do
    ActiveRecord::Base.connection.drop_table :parents, if_exists: true
    ActiveRecord::Base.connection.drop_table :children, if_exists: true
    ActiveRecord::Base.connection.create_table :parents
    ActiveRecord::Base.connection.create_table :children do |t|
      t.references :parent
    end

    stub_const 'Parent', Class.new(ActiveRecord::Base)
    stub_const 'Child', Class.new(ActiveRecord::Base)
  end

  describe 'has_one' do
    subject(:record) { Parent.create(child: Child.new) }

    before do
      Parent.class_eval 'has_one :child, inverse_of: :parent'
      Child.class_eval 'belongs_to :parent, inverse_of: :child'
    end

    it { expect { record }.not_to raise_error }
  end

  describe 'has_many' do
    subject(:record) { Parent.create(children: [Child.new]) }

    before do
      Parent.class_eval 'has_many :children, inverse_of: :parent'
      Child.class_eval 'belongs_to :parent, inverse_of: :children'
    end

    it { expect { record }.not_to raise_error }
  end
end
```

The Parent model in the first case has a 'has_one' association and in the
second case there is a 'has_many' association. The test in each case checks
that an instance can be created. When running each individually (`rspec
spec/test_spec.rb:24` and `rspec spec/test_spec.rb:35`) they both pass but
when run together I get:

expected no Exception, got
#<ActiveRecord::InverseOfAssociationNotFoundError: Could not find the
inverse association for parent (:children in Parent)> with backtrace:

with the second test. This suggests to me that the tests are not correctly
isolated, and the configuration of the first is affecting the second. I had
hoped that the stubbed constants for the models would ensure that all
configuration is discarded but is there some sort of cache in ActiveRecord
that needs to be cleared? Or maybe what I'm doing is crazy?

Thanks,

Joe

-- 
You received this message because you are subscribed to the Google Groups 
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rspec/CAKRXwc0J5pTcJnb-01tE8Nq8iS9e8y4grOMqf_vabidC2w-tDw%40mail.gmail.com.

Reply via email to