Fixtures when using Rails (My environment Rails 4.2)
Why when running a test, why does it error when a fixture exists but there isn't a table with the same name? And why does the fixture require to have a matching column in the table?
Example 1: (table does not exist)
create a fixture joes.yml (Joes table does not exist)
Run the rake test:integration
The error you'll get is:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: joes: DELETE FROM "joes"
Example 2: (table exists, but column does not)
create a fixture products.yml. This case the table Products does exist
add a yml block with a name of a column you don't have in the products table. example add an entry other: bla in the products.yml file
Run the rake test:integration
ActiveRecord::Fixture::FixtureError: table "products" has no column named "other".
I thought I could use fixtures as common place to reference in my tests, but doesn't need to match my DB.
Fixtures are your data, they still require a place to go!
"Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent written in YAML. There is one file per model."
http://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures
They are not some sort of in memory replacement for a testing database, they just allow you to pre-populate your test database with values, so that you can test more conveniently without having to put lots of data in, when setting up a test run. That's all.
Related
I've added a dependency to both order and order_items fixtures (which already existed), but I'm receiving the following error every time I run my rspec worker test.
ActiveRecord::StatementInvalid:
Mysql2::Error: Table 'inventory_test10.order_packages' doesn't exist: SHOW FULL FIELDS FROM `order_packages` /*controller:,action:,line:*/
I have an order which has many order_items and many order_packages. order_items also belong to order_packages. Therefore, I am able to do:
order.order_items.each do |oi|
put oi.order_package.status
end
The original issue was that status wasn't recognized for nil class because an order_packages.yml fixture was never created. I've tried several rake tasks, but I'm not super familiar with fixtures, migrations, rake tasks, etc and I'm not sure if I accidentally caused the error running multiple taks. Below is a snippet from a blog that warned about running the command multiple times - http://brandonhilkert.com/blog/using-rails-fixtures-to-seed-a-database/:
rake db:fixtures:load FIXTURES=credit_card_types
A word of warning, if we run this command multiple times, it will seed
the table multiple times. It’s not idempotent.
Other tasks I ran:
FIXTURES=orders; rake db:fixtures:load
rake db:fixtures:dump (didn't work - error)
rake db:fixtures:drop (didn't work - error)
Thanks in advance for any suggestions!
Your test framework should automatically load fixtures at the beginning of the test run, and delete them at the end of the test run. You should not need to load fixtures yourself.
Fixtures load data into tables; they do not alter the database structure. Migrations can alter the database by creating/dropping tables, adding/removing columns, etc. If you are having an issue with a missing table, it is very like a migration problem.
I recommend a review of the Guide to Testing Rails Applications, and (if you are using RSpec) the rspec-rails documentation, which explain these concepts in greater depth.
Hi i probably have a simple question.
I have this database with moodboard templates.
I want to transport it to the server with capistrano but in my seeds.rb file there is only all the seeds and if i run them again a lot of data gets inserted twice.
I normally run:
rake db:seed
But i would like to see another command
How can i make a separate seed file to execute on its own.
You can either delete your seeds before insert in seeds.rb or check the count of the model rows or check for the id if the item you're looking to insert before you insert it in your seeds.rb. Basically, I think you just need to add some checks before you insert additional data. I could provide a more specific answer if you posted your seeds.rb.
I try to run this simplest unit test:
test "the truth" do
assert true
end
like this:
ruby -Itest test/unit/my_model_test.rb
(there is the only one test in the file, and actually in the whole site)
it fails with this message:
ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: column email is not unique: INSERT INTO "users"... [some values to insert here]
now I do have a table named "users" but other than that I have never asked to do any tests on it nor do I even have such tests. Where does this error come from? How do I run just my test?
EDIT: the "users" table comes from the devise gem if that helps
Quote from http://guides.rubyonrails.org/testing.html
Rails by default automatically loads all fixtures from the
test/fixtures folder for your unit and functional test. Loading
involves three steps:
Remove any existing data from the table corresponding to the fixture
Load the fixture data into the table
Dump the fixture data into a
variable in case you want to access it directly
So I think you need to check those fixtures. Also I suggest you to read that tutorial. It is very well written.
Per my requirements, I have created models for querying external database (different from the one that the rails app uses) for some of the data.
I am trying to write tests around these models and want to separate the "sample test data" from the actual tests.
I thought I could put the data in a yml file and load it into a hash, but it did work out :(
Added sample test data to a fixture file name 'external_database.yml'
Put the below code in setup, in the test file
ext_data = YAML.load_file(Rails.root.to_s + "/test/fixtures/ext_data.yml")
But I am stuck with the below error
1) Error:
test_should_errorout_for_invalid_market_zip(ExtDBTest):
ActiveRecord::StatementInvalid: Mysql::Error: Table 'rails_app_db.ext_data' doesn't exist: DELETE FROM ext_data
What is the best way to do what I want done?
I guess your problem is that the schema of that external database is not contained in your schema.rb-file and/or migrations. These are used to setup your test-database before you run the tests.
So the attempt is made to write those fixtures into non-existing tables - with the result you see above.
Multiple database-connections in unit tests are generally a pain. Consider creating an sqlite-file for the data of the external dependencies and configure your test-environment to use this file - or a copy of it, in case you need to mutate data.
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.