ajorgensen
ajorgensen

Reputation: 5151

Odd behavior with ActiveRecord and Tests

I have two ActiveRecord models that looks like this:

class Foo < ActiveRecord::Base
  after_commit { puts 'after commit in Foo' }
end

class Bar < ActiveRecord::Base
   after_commit { puts 'after commit in Bar' }
end

And then I have two tests that look like this:

test/unit/foo_test.rb

class FooTest < ActiveSupport::TestCase
  setup do
    puts 'Creating Foo'
    @foo = Foo.create
 end

 should 'foo exists' do
   assert [email protected]?
 end
end

test/unit/bar_test.rb:

class BarTest < ActiveSupport::TestCase
  self.use_transactional_fixtures = false

  setup do
    pits 'Creating Bar'
    @bar = Bar.create
 end

 should 'bar exists' do
   assert [email protected]?
 end
end

But when I run these tests together I get the following output:

Creating Foo
Creating Bar
after commit in Foo
after commit in Bar

I was under the impression that Rails by default wrapped the active record stuff in a transaction and then did a rollback at the end of each test. I have tried explicitly setting use_transactional_fixtures = true but that has not yielded any results.

My question is what is going on here? It would seem that active record is creating the callback chain for Bar and then it's not getting cleared out after the test is done. I have also tried using DatabaseCleaner and explicitly destroying @bar in a teardown callback at the end of the test but none of that has worked.

Edit: Looks like it could be a problem in rails: https://github.com/rails/rails/pull/3300

Upvotes: 0

Views: 147

Answers (1)

ajorgensen
ajorgensen

Reputation: 5151

Turns out there's a bug in rails that causes records in a transaction to stick around even after the actual database has been rolled back. Here is the discussion: https://github.com/rails/rails/pull/3300

You can use the following method (as suggested in the github thread) to clear the active transactions between test runs if needed:

def teardown_fixtures
        if run_in_transaction? && ActiveRecord::Base.connection.open_transactions != 0
    ActiveRecord::Base.connection.rollback_db_transaction

    ActiveRecord::Base.connection.send(:rollback_transaction_records, true)
    if ActiveRecord::Base.connection.instance_variable_get('@_current_transaction_records')
      ActiveRecord::Base.connection.decrement_open_transactions
    end

    ActiveRecord::Base.clear_active_connections!
  end
end

Upvotes: 1

Related Questions