medihack
medihack

Reputation: 16627

Turn off transactional fixtures for one spec with RSpec 2

How do I turn off transactional fixtures for only one spec (or Steak scenario) with RSpec 2? I tried some things found on the web without any success.

This leads to an undefined method exception.

describe "MyClass without transactional fixtures" do
  self.use_transactional_fixtures = false
  ...
end

This simply does nothing (transactional fixture is still on):

describe "MyClass without transactional fixtures" do
  RSpec.configure do |config|
    config.use_transactional_fixtures = false
  end
  ...
end

What else could I try?

Upvotes: 46

Views: 24277

Answers (10)

Rodrigo Dias
Rodrigo Dias

Reputation: 1340

I was able to use the truncation method in specific tests, and the transaction method as the default. This was done with the config below.

In the rails helper.

RSpec.configure do |config|
  ...
  config.use_transactional_fixtures = false

  config.around do |example|
    # default strategy is transaction
    use_truncate = example.metadata.fetch(:use_truncate, false)

    strategy = use_truncate ? :truncation : :transaction
    DatabaseCleaner.strategy = strategy

    DatabaseCleaner.cleaning do
      example.run
    end
  end
end

In the test that you want to use the truncation method:

it 'my spec using truncate', use_truncate: true do
   ...
end

Upvotes: 0

kuboon
kuboon

Reputation: 10191

Thanks for Maxence's answer, I found very practical hack.

You can write this magical phrase def self.uses_transaction?(_method) = true in any describe/context block.

For example:

describe "transactional test" do # or context
  def self.uses_transaction?(_method) = true

  # any testcase in this block is out of transaction
end

Upvotes: -1

Dende
Dende

Reputation: 594

I needed to switch off transactional fixtures for only one test in the suite. Nothing written above worked for me (Rails 6.1.7.6).

I had to write the test setup like that

describe '.method', use_transactional_fixtures: false, truncate: true do
end

And in the rails helper inside Rspec.config block, I added following code:

  config.before do |example|
    config.use_transactional_fixtures = (example.metadata[:use_transactional_fixtures] || true)

    DatabaseCleaner.strategy = if example.metadata[:truncate]
                                 :truncation
                               else
                                 :transaction
                               end
    DatabaseCleaner.start
  end

  config.after do
    config.use_transactional_fixtures = true
  end

  config.append_after do
    DatabaseCleaner.clean
  end

This allowed me keeping transactional fixtures for all other tests in the suite

Upvotes: 1

Maxence De Rous
Maxence De Rous

Reputation: 166

The 2023 answer for RSpec 6.0:

uses_transaction "doesn't run in transaction"

it "doesn't run in transaction" do
  expect(ActiveRecord::Base.connection.transaction_open?).to eq(false)
end

it "runs in transaction" do
  expect(ActiveRecord::Base.connection.transaction_open?).to eq(true)
end

https://github.com/rspec/rspec-rails/blob/v6.0.1/spec/rspec/rails/fixture_support_spec.rb#L21

Upvotes: 2

Sukeerthi Adiga
Sukeerthi Adiga

Reputation: 589

Use use_transactional_tests instead of use_transactional_fixtures When Rspec 2.3.8 is being used

def without_transactional_fixtures(&block)
  self.use_transactional_tests = false

  before(:all) do
    DatabaseCleaner.strategy = :truncation
  end

  yield

  after(:all) do
    DatabaseCleaner.strategy = :transaction
  end

  self.use_transactional_tests = true
end

Upvotes: 3

Gabriel Queiroz
Gabriel Queiroz

Reputation: 111

I mixed both answers and it worked for me on RSpec 3:

config.around(:each, use_transactional_fixtures: false) do |example|
  self.use_transactional_fixtures = false
  example.run
  self.use_transactional_fixtures = true

  DatabaseCleaner.clean_with(:deletion)
end

You can then use it in the describe, context or it block

describe 'my test', use_transactional_fixtures: false do
   ...
end

Upvotes: 11

phil pirozhkov
phil pirozhkov

Reputation: 4909

Not sure if that applies to RSpec2, but works fine with 3.

config.use_transactional_fixtures = true
config.around(:each, use_transactional_fixtures: false) do |example|
  self.use_transactional_tests = false
  example.run
  self.use_transactional_tests = true
end

Mind the use_transactional_fixtures (rspec-rails option) and use_transactional_tests (activerecord fixtures option) difference.

Upvotes: 7

Guilherme
Guilherme

Reputation: 1146

I've did it this way, with database_cleaner, in order to test code that uses transactions (which will conflict with transactional_fixtures or any other strategy to make transactional tests e.g. DatabaseCleaner.strategy = :truncation or :transaction):

# spec_helper.rb
config.use_transactional_fixtures = false
config.around(:each, :testing_transactions => true) do |ex|
    DatabaseCleaner.strategy = nil
    ex.run
    DatabaseCleaner.strategy = :truncation
end

and in my test cases:

it "should not save if one of objects are invalid", :testing_transactions => true

Upvotes: 10

mattias
mattias

Reputation: 465

I usually add a helper like this:

def without_transactional_fixtures(&block)
  self.use_transactional_fixtures = false

  before(:all) do
    DatabaseCleaner.strategy = :truncation
  end

  yield

  after(:all) do
    DatabaseCleaner.strategy = :transaction
  end
end

Which lets me turn off transactional fixtures for a specific block in the specs:

describe "doing my thing" do
  without_transactional_fixtures do
    it "does something without transaction fixtures" do
      ...
    end
  end
end

Upvotes: 37

Lailson Bandeira
Lailson Bandeira

Reputation: 764

This used to be a bug (see ticket #197), but I seems to be okay now. I just don't know if it will work on a per test base (probably not). If you want to do this, you can disable transactional fixtures globally by putting config.use_transactional_fixtures = false on the spec_helper.rb and use DatabaseCleaner to set that.

I've had a similar problem when testing pages with javascript on the browser (a scenario that does not work with transactional fixtures). Here's how I managed to work around it: http://github.com/lailsonbm/contact_manager_app

Upvotes: 9

Related Questions