views:

1096

answers:

4

I am using seeds.rb to populate some State model reference data:

State.create :name => 'Alabama', :abbreviation => 'AL'
State.create :name => 'Alaska', :abbreviation => 'AK'
# ...

Although I am not using state fixtures (since it's seed data to begin with, I think it wouldn't be DRY to have to duplicate this purely for tests), the Rails testing framework seems to delete all the State seed data during testing. (I am dropping, recreating, migrating and reseeding the test db, and confirmed the data is there prior to a unit test running.)

The result is this assertion succeeding in seeds.rb but failing in a one-line test:

assert_equal 51, State.all.size

1) Failure:
test_state_seeds_are_present(StateTest) [/test/unit/state_test.rb:24]:
<51> expected but was
<0>.
1 tests, 1 assertions, 1 failures, 0 errors

I have tried both explicitly listing non-State models in the base test class fixtures statement, as well as flipping the transactional fixtures flag (as expected, this only affects records created during the test). Naturally the test under consideration is not itself deleting these records.

The State records are always deleted. Is there a way to tell Rails to just get its hands off the seed data? Do I need to duplicate all the data in fixtures to make sure it gets re-loaded? Short of a major political event, I would expect the state data to be relatively stable.

tia

+4  A: 

Tests delete all the data from the database and then load your fixtures (if you have any).

You need to get your test helper to load the seed file before the tests run. There are a couple ways to do that, check out my similar question: How to load db:seed data into test database automatically?

The easiest way is probably just to add

require "#{Rails.root}/db/seeds.rb"

to the top of your test_helper.rb file (assuming you use the built-in testing framework).

Luke Francl
This doesn't work for me, if i add that line to my fixture it works ok, but if i put it in test_helper.rb, the seed data seems to have vanished before my tests are reached.
Jon
Do you have a fixture yml file for a class that you're trying to populate in your seed file? Because that will blow away all data when fixtures run. Delete the fixture file for seeds; or if you can't do that use Simone's example where the fixture data is loaded before every single test.
Luke Francl
ahh, I had commented out my .yml file, but that seems to be not enough, its mere presence causes the seed data to be overwritten. Deleted it, and all is well, thanks for your help Luke
Jon
yeah, it's a bit counter-intuitive but if the yml file is there and empty, it still deletes the contents of that table.
Luke Francl
+4  A: 

The "seed" feature is not integrated into the test architecture. Tests are built around fixtures and each time you run the test suite, Rails loads the data from the fixtures and replaces the existing content.

However, having the database populated with your seed data is really straightforward.

In your test_helper.rb file add a new setup method in the base ActionSupport::TestCase class.

class ActionSupport::TestCase < ...

  setup :load_seeds

  protected 

    def load_seeds
      load "#{Rails.root}/db/seeds.rb"
    end

end
Simone Carletti
This is going to reload your seed data before every test case, which given transactional fixtures you probably don't need to do. As long as the seed data is supposed to maintain constant (which it should) you should only have to load it once.
Luke Francl
That's what I thought Luke, but it appears to be getting deleted regardless, so it sounds like I'm going to have to implement some sort of workaround to make sure it is present in the db for tests.
aaron
Do you have a states.yml file in your fixtures directory? Even if it's empty it will result in your states data getting deleted. I always make sure to delete fixtures for my seed data tables (actually I don't really use fixtures at all any more but that's another story).
Luke Francl
Yes, I do/did have a states.yml (empty). Deleting it (well, renaming it) was one of the things I tried but it didn't seem to help. But I will give it another shot because I'm still interested to see if I can prevent it from even trying to delete the data.
aaron
Did my solution work?
Simone Carletti
A: 

I agree with weppos as to the best way to do this, however for the sake of completeness and for the sake of people who may already have fixture files you can take the other approach and seed your database from the existing fixtures.

This is accomplished by doing something like the following in the db/seeds.rb file

RAILS_FIXTURES = "#{Rails.root}/spec/fixtures"

models_loaded_from_fixtures = %w[Modela Modelb Modelc ....]

models_loaded_from_fixtures.each do |model|
  Fixtures.create_fixtures(RAILS_FIXTURES, "#{model.tableize}")
  puts "Loaded #{model.constantize.all.size} #{model.pluralize}"
end

You could alternatively read the fixures directory and create an array of file names to process, I chose the above process as I wished to be able to specify which of my many existing fixtures I wished to seed the DB with.

Steve Weet
A: 

I question the need to write a test like that in the first place. Are you testing that the seed data rake task works properly or do you want to test the behavior of your implementation of the State class? I'm assuming the latter, so I would write tests that focus on the behavior and use Factory Girl (or similar) since you mention that you're not using fixtures. Make sure to remove the fixtures :all line from test/test_helper.rb.

To inject a task into the normal flow of running tests, this is an approach that has always worked for me:

namespace :test do
  task :force_environment do
    ENV['RAILS_ENV'] = 'test'
    RAILS_ENV.replace('test')
  end
end

%w(test:units test:functionals test:integration).map do |task_name|
  task = Rake::Task[task_name]
  task.clear_prerequisites

  task.enhance %w(db:test:prepare test:force_environment db:seed)
end

Just put that in a file called lib/tasks/testing.rake and it will get picked up when you next run rake test or other test-related task.

Patrick Reagan
Hi Patrick. I actually don't need to test the State model per se, that was just an example demonstrating that the seed data is not present. The state model (reference data) is used in validating addresses, and address validation tests were failing because the state data was not in the db.
aaron
That makes more sense. The Rake task should work for you, but it sounds like you got things working.
Patrick Reagan