43

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?

medihack
  • 16,045
  • 21
  • 90
  • 134
  • it's really wired to want that. because you can't know what you have in your database. – shingara Oct 04 '10 at 09:32
  • I hope that's not true for your code, too ;-) But seriously, for some testing scenarios you have to disable the transactional fixtures. For example, like in my case, to test Thinking Sphinx. Sphinx needs to update the search index from the "outside". And so it has to know the database content at a specific time. – medihack Oct 13 '10 at 16:49
  • Just one thing to note; At least in my environment ( Rails4 rspec 2 ) if you for some reason include the rspec/rails_helper in any of your rspec files, it will cause any test after it in the suite or in subsequent files to be run transactionally again. – Wedge Martin Sep 16 '15 at 13:47

7 Answers7

35

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
mattias
  • 445
  • 5
  • 6
  • are you sure it works? i've tried here to test something that was using rails transactions and not worked :( – Guilherme May 18 '12 at 03:26
  • 2
    You can just change the DatabaseCleaner.strategy in a before/after block of your specs too. – Matt Connolly Oct 30 '13 at 02:29
  • 1
    Don't we have to set the ```self.use_transactional_fixtures``` to true again? in after(:all) block? I guess it will set as false for other specs which will run. – Sukeerthi Adiga Nov 19 '18 at 09:21
10

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
Guilherme
  • 1,126
  • 9
  • 17
9

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

Lailson Bandeira
  • 754
  • 1
  • 7
  • 18
  • 1
    Thanks for pointing me to the ticket, Lailson. Answer accepted :-) I also use a workaround as I don't like to disable transactional fixtures globally (too slow). I simply do a MyClass.connection.commit_db_transaction() after the objects were created. Then I do the test and afterwards delete the database entries. That works fine, and all other tests still use the transactional feature. – medihack Oct 13 '10 at 12:51
  • Nice. As I said, you can do this cleanly with DatabaseCleaner (see the github repo README I pointed to know how to do this). But your solution is viable too, just a bit error-prone. But if it's working and you're satisfied, cool… =) – Lailson Bandeira Oct 14 '10 at 02:10
  • I tried `MyClass.connection.commit_db_transaction` but it left the connection in an odd state where it thought it had an open transaction but it did not. This made certain active record commands not work and also led to warnings. This seemed to fix that problem, actually closing the transaction in the db and updating the connection to know it no longer had an open transaction: MyClass.connection..transaction_manager.commit_transaction – nbrustein Sep 20 '17 at 14:20
9

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
6

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.

phil pirozhkov
  • 4,740
  • 2
  • 33
  • 40
3

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
Sukeerthi Adiga
  • 531
  • 5
  • 9
2

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

Maxence De Rous
  • 158
  • 1
  • 2
  • 5