I have a good half-dozen fixtures in my Rails test suite - some quite large - that represent static look-up tables in the database. Since their values theoretically don't change, I'd like to save the time of wiping and reloading the tables between each test. Is there a trick/plug-in/gem/hack to demarcate these fixtures as only needing to be loaded once before all the tests run and not wiped between each?
You can desactivate rollback transaction in all your test.
Or you can add this fixtures before all of your test. Before the begin of transaction.
Related
My legacy code is using DatabaseCleaner which wipes out database after each test being done. However it also wipes out loaded fixtures data and causes some tests which are using fixtures to fail, something like:
ActiveRecord::RecordNotFound Exception: Couldn't find Country with 'id'=593363170
To make them work together, how can I rewrite all fixtures back to database during test? (I mean not rake tasks)
Solution:
Set self.use_transactional_fixtures = false
at the beginning of the file before which you want to reload fixtures.
Or use use_transactional_tests in Rails 5.
Do not set it in spec_helper as it applies globally so conflicts with DatabaseCleaner.
I've read some topics about not using RSpec's before all callback, but none of those answered my question: I normally got constant-like records in my db. They are not changeable to my users and are required as 'belongs_to' subject in every 'Order' (the most created Model in my app) object. It would feel unnatural for me to create a factory for this model.
So where am I to create those records (most of the time it is just couple of them)?
You could populate your test db using
rake db:seed RAILS_ENV=test
before running your tests the first time, after that they will be available for every run. Be careful though not to change the test db during the tests, to avoid polluting your seed data.
I've been in Factory land for the past few years and have decided to come back to fixtures but am running into a problem.
In my test_helper.rb I have
class ActiveSupport::TestCase
fixtures :all
end
Then in an individual test case I might be doing something like users(:one) however the data for users(:two) and the data for other tables that I am not calling on seems to be present in the test database.
So, is this the expected behavior? I have a hard to believing it is, seems strange from an isolated testing perspective.
This happens because you load all the fixtures at once from fixtures :all statement. A rule of thumb in tests is to load only the required data for a given test (not all). This also could slow down your test running time.
If you want to load only the selected fixtures you could do
fixtures :<fixture name>
Ex:
fixtures :users
Read more about fixtures.
One more thing, do you have a particular reason to comeback to fixtures. Factories are the way to go; they allow you do organize your test data cleanly.
Read more about factories.
We have a ton of non-user data: 500 product types that haven't changed in 20 years, 200GB of geospatial data that never changes (Queens is always 40.73N/73.82W)... etc. It's the same in Development and Production. It should be the same in Test, but the during testing Rails empties all of the test tables, and it takes a ton of time to re-populate during testing.
What is the Rails way to partition this non-user data so that it doesn't have to be repopulated in Test?
The documentation for this is found in the Fixtures class. (Search for "Transactional fixtures" on that page.)
The example they give starts out like this:
class FooTest < ActiveSupport::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
...
One of the projects I work on uses a test database with zero fixtures, so we just define this globally in test_helper.rb.
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
jdl shows you the settings to use for enabling and disabling transactional_fixtures, you should be able to set:
# Use self in ActiveSupport::TestCase if you don't have a config block
# in test/test_helper.rb
#
config.use_transactional_fixtures = false
And stop Rails from trying to load fixtures before each run of your tests. The downside is you can't assume all your fixtures are loaded into the DB.
Real Answer
You have too much data in your fixtures. The Railsy thing to do it load only the necessary data in test fixtures; You do not need 200G of geospatial data (what freaking dataset is that anyway? that sounds way too big), and you probably don't need all 500 products.
Tests are for your code, so only include the few geospatial points you need for a test, or only include a few products with unique properties. Keep the DB light enough to be loaded quickly.
Your test fixtures should be separate from you application bootstrapping data, take advantage of that.
Real Real Answer
Don't touch the database in your tests (or, touch it very little). The database is slow and fixtures are difficult or impossible to maintain well. Instead, try using a stubbing framework like Mocha or flexmock. It's faster, and makes your tests read in a clearer manner. Tests are for code, you can stub the database out of the situation and trust that ActiveRecord works (because...it's tested too! :-).
If you do choose to stick with fixtures, I recommend using factory_girl instead of the built in Rails fixtures. You'll have a much better starting point.
In a Rails application, I need a table in my database to contain constant data.
This table content is not intended to change for the moment but I do not want to put the content in the code, to be able to change it whenever needed.
I tried filling this table in the migration that created it, but this does not seem to work with the test environment and breaks my unit tests. In test environment, my model is never able to return any value while it is ok in my development environment.
Is there a way to fill that database correctly even in test environment ? Is there another way of handling these kind of data that should not be in code ?
edit
Thanks all for your answers and especially Vlad R for explaining the problem.
I now understand why my data are not loaded in test. This is because the test environment uses the db:load rake command which directly loads the schema instead of running the migrations. Having put my values in the migration only and not in the schema, these values are not loaded for test.
What you are probably observing is that the test framework is not running the migrations (db:migrate), but loading db/schema.rb directly (db:load) instead.
You have two options:
continue to use the migration for production and development; for the test environment, add your constant data to the corresponding yml files in db/fixtures
leave the existing db/fixtures files untouched, and create another set of yml files (containing the constant data) in the same vein as db/fixtures, but usable by both test and production/development environments when doing a rake db:load schema initialization
To cover those scenarios that use db:load (instead of db:migrate - e.g. test, bringing up a new database on a new development machine using the faster db:load instead of db:migrate, etc.) is create a drop-in rakefile in RAILS_APP/lib/tasks to augment the db:load task by loading your constant intialization data from "seed" yml files (one for each model) into the database.
Use the db:seed rake task as an example. Put your seed data in db/seeds/.yml
#the command is: rake:db:load
namespace :db do
desc 'Initialize data from YAML.'
task :load => :environment do
require 'active_record/fixtures'
Dir.glob(RAILS_ROOT + '/db/seeds/*.yml').each do |file|
Fixtures.create_fixtures('db/seeds', File.basename(file, '.*'))
end
end
end
To cover the incremental scenarios (db:migrate), define one migration that does the same thing as the task defined above.
If your seed data ever changes, you will need to add another migration to remove the old seed data and load the new one instead, which may be non-trivial in case of foreign-key dependencies etc.
Take a look at my article on loading seed data.
There's a number of ways to do this. I like a rake task called db:populate which lets you specify your fixed data in normal ActiveRecord create statements. For getting the data into tests, I've just be loading this populate file in my test_helper. However, I think I am going to switch to a test database that already has the seed data populated.
There's also plugin called SeedFu that helps with this problem.
Whatever you do, I recommend against using fixtures for this, because they don't validate your data, so it's very easy to create invalid records.