DatabaseCleaner / database_cleaner-active_record

Strategies for cleaning databases using ActiveRecord. Can be used to ensure a clean state for testing.
MIT License
63 stars 64 forks source link

Cleaning does not occur on subsequent specs when there are two databases and shared examples #110

Open coderberry opened 4 months ago

coderberry commented 4 months ago

This might be a rare use case, but I have an app that uses two databases. Here's a snippet from my database.yml file:

test:
  primary:
    <<: *default
    database: primary_test

  cache:
    <<: *default
    database: secondary_test

I have one ActiveRecord model (RawDatum) set up to read/write to/from the secondary database.

Here's a summarized version of my RSpec spec:

require "rails_helper"

describe SomeJob, type: :job do
  shared_examples "perform" do |api_server_id, expected_records_count|
    describe "#perform" do
      it "inserts records into RawDatum" do

          # This will fail on the 2nd `it_behaves_like` below
          expect(RawDatum.count).to eq(0)

          described_class.perform_now(api_server_id)

          expect(RawDatum.count).to eq(expected_records_count)
      end
    end
  end

  describe "API One" do
    it_behaves_like "perform", 1, 822
  end

  describe "API Two" do
    it_behaves_like "perform", 2, 439
  end
end

Here is my spec/support/database_cleaner.rb file:

require "database_cleaner"

# see https://github.com/DatabaseCleaner/database_cleaner#how-to-use
RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner[:active_record, db: :primary].strategy = :transaction
    DatabaseCleaner[:active_record, db: :cache].strategy = :transaction

    DatabaseCleaner[:active_record, db: :primary].clean_with(:truncation)
    DatabaseCleaner[:active_record, db: :cache].clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner[:active_record, db: :primary].start
    DatabaseCleaner[:active_record, db: :cache].start
  end

  config.after(:each) do
    DatabaseCleaner[:active_record, db: :primary].clean
    DatabaseCleaner[:active_record, db: :cache].clean
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end
end
etagwerker commented 3 months ago

@coderberry Interesting problem. I'm not 100% sure what could be the problem.

Here are some options:

  1. I don't think you need all of this:
  config.before(:each) do
    DatabaseCleaner[:active_record, db: :primary].start
    DatabaseCleaner[:active_record, db: :cache].start
  end

  config.after(:each) do
    DatabaseCleaner[:active_record, db: :primary].clean
    DatabaseCleaner[:active_record, db: :cache].clean
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end 

Could you test with one (cleaning) or the other (start+clean)?

If you get the same results, I'd probably keep the start+clean and get rid of the cleaning call.

  1. It might be an issue due to multiple database connections?

Another idea is that you could test this PR: https://github.com/DatabaseCleaner/database_cleaner-active_record/pull/108 -- it might be related to your problem.