views:

541

answers:

5

Where does Rails store data created by saving activerecord objects during tests?

I thought I knew the answer to that question: obviously in the _test database. But it looks like this is not true!

I used this system to test what's happening to saved ActiveRecord data during rspec tests:

$ rails -d mysql test

$ cd test

$ nano config/database.yml ...

... create mysql databases test_test, test_development, test_production

$ script/generate rspec

$ script/generate rspec_model foo

edit Foo migration:

class CreateFoos

$ rake db:migrate

edit spec/models/foo_spec.rb:

require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe Foo do
  before(:each) do
    @valid_attributes = {
      :bar => 12345
    }
  end

  it "should create a new instance given valid attributes" do
    foo = Foo.new(@valid_attributes)
    foo.save
    puts "sleeping..."
    sleep(20)
  end
end

$ rake spec

When you see "sleeping...", change to another open terminal with a mysql session conneted to the test_test database and do:

mysql> select * from foos;
Empty set (0.00 sec)

Why doesn't the mysql session show any records in the test_test database while the test is running?

+10  A: 

Items in the test database are erased by default after each test is run, by design. This is done to make sure that each of your tests has its own sandbox to play in that doesn't cause any interactions with the tests before it.

Again, this is by design. You don't want tests that are manipulating the same set of data (or rely on synchronous execution), because there is no guarantee of execution order.

However, I believe if you modify you test/test_helper.rb file to say this:

self.use_transactional_fixtures = false

instead of

self.use_transactional_fixtures = true

It will cause the data in your test database to persist.

ALSO: My advice is specifically designed to work with Test::Unit, not RSpec. However, I imagine that there is a similar setting your spec_helper.rb you should be looking for.

Derek P.
+1  A: 

You can observe records being added to the test database with:

tail -f log/test.log

You should see the transactions flying by as the tests are run.

_martinS_
A: 

@Derek, many thanks - your suggestion worked.

That the database is cleared before each test is clear to me. But why does the mysql query show no data in the database while the test is running?

@Martin, from the log I can see that a ROLLBACK is happening. Does this have something to do with why the data is not visible while the test is run?

Rich Apodaca
Database transactions are isolated, and changes made are only visible on the connection of the transaction till commit. Think of it as each transaction working in a different copy of the database. When it commits, then it writes those changes for all to see.If it rolls back, they are never seen.
madlep
If my suggestion worked, could you please select my answer as the "chosen one" for this question? Thanks :)
Derek P.
+2  A: 

"But why does the mysql query show no data in the database while the test is running?"

Because it's in a transaction. If you turn transactional fixtures off your tests will run much slower than before.

jshen
A: 

Thanks - these answers helped a lot!

Rich Apodaca