I'm still a bit of a newbie, and I'm stumped: I have a 'find_by' statement that works fine when it's executed in a production environment, but it fails during a test, with what is, as far as I can determine, identical input.
I have a very simple table, populated by seeds.rb as follows:
Nonprofit.create!(id: 1, name: "Nonprofit number 1")
Nonprofit.create!(id: 2, name: "Nonprofit number 2")
In my sessions controller, I have the following two statements:
puts "=======>" + params[:nonprofit_id] + "<=============="
nonprofit = Nonprofit.find_by(id: params[nonprofit_id])
puts "=======>" + nonprofit.name + "<=============="
In the production environment, the log shows this:
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Mm7qVchebMORY5QBOlvl1ac69m1ACwttXcE71LbfHnHH2RqpB6mSP+wFxodop/9Mgv/NlLO9V9NVEcTU1a54tw==", "session"=>{"email"=>"jane#rich.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "nonprofit_id"=>"1", "commit"=>"Log in"}
==================>>>1<=========
Nonprofit Load (0.3ms) SELECT `nonprofits`.* FROM `nonprofits` WHERE `nonprofits`.`id` = 1 LIMIT 1
==================>>> Nonprofit number 1
In other words, ActiveRecord finds the correct table entry using the id value of 1.
The log from the test run shows exactly the same output from the 'puts', but then it errors out on the second 'puts' because (presumably) the find_by didn't find the record. Here's the log from the test run:
Running:
==================>>>1<=========
E
Finished in 0.467105s, 2.1408 runs/s, 0.0000 assertions/s.
1) Error:
UsersIndexTest#test_index_as_non-admin:
NoMethodError: undefined method name' for nil:NilClass
app/controllers/sessions_controller.rb:14:increate'
test/test_helper.rb:19:in log_in_as'
test/integration/users_index_test.rb:29:inblock in '
Any ideas/suggestions? Alternatively (or in addition) how can I cause the test run log to show the active record query, like the log shows for the production run?
Thanks!
Your test can't find the record you're looking for because Rails does not load seed.rb into the test database.
You should use something like FactoryGirl, Fixtures or just create the records in the before(:each) block. Any Rails testing tutorial will have something to say about Fixtures, FactoryGirl or some other way to get data into your tests. This may be a good way to start.
Alternatively, if you really need to load what you have in seeds.rb into your testing database, you could try doing this.
Rails works with different environments. While testing your're (duh) on test environment. When running your application locally (with rails server) you are on development environment. When running on a server, it's supposed to be on production environment.
Each environment has its own database. I suppose you ran 'rake db:seed' and thought it'd populate your test database, but it's not true. That's why it isn't finding the record - on test database it doesn't exist.
As pointed out by #pggaspar you should be working with factories or fixtures to populate your test database.
Related
I've got some model code that calls to the database with a simple find():
#thing = Thing.find(id)
I have data seeded in the database for the test environment. If I open the console in test (rails c -e test), I can run Thing.find(1) and get a result fine, however when I run a test that calls the method shown above, it reports that it cannot find a record with the id of 1.
I assume I am misunderstanding the relationship between test seed data and the tests being run against that database. Why do I see seed sin the test DB but the test doesn't?
A more conventional way of doing this would be to create fixtures (or factories if using FactoryBot) and call these factories in your test setup. As previous answers have said, hardcoding test ID's will likely return RecordNotFound due to auto-incrementing.
I'm trying to load some seed data into an app with heroku. I'm more looking just to insert a bunch of seed (sample) data into my app so my client can see it with a lot of objects. (Imagine a demo e-commerce app - I want to be able to show a couple dozen sample products without manually entering them in)
My seed data works fine in development but in production, the one HMBT association causes the below error:
WARNING: Rails was not able to disable referential integrity.
This is most likely caused due to missing permissions.
Rails needs superuser privileges to disable referential integrity.
Heroku documentation said this this so I tried a conditional to remove the referential integrity on production in my seeds file(see below), but now seeds won't run. It just does this:
Running rake db:seed on ⬢ app... up, run.1225 (Free)
ActiveRecord::SchemaMigration Load (1.7ms) SELECT "schema_migrations".* FROM "schema_migrations"
Here's my seeds file below:
if Rails.env.development?
ActiveRecord::Base.connection.disable_referential_integrity do
end
1.upto(14) do |n|
pic_one = File.open(File.join(Rails.root,'app/assets/images/file1.jpg'))
pic_two = File.open(File.join(Rails.root,'app/assets/images/carpet_2/file2.jpg'))
image = PicAttachment.create!([
{picture: pic_one, w_dream_id: "#{n}"},
{picture: pic_two, w_dream_id: "#{n}"},
])
rug = Product.create!(
pic_attachments: image
end
if Rails.env.development?
end
end
Does anyone where I'm going wrong?
The link you posted states that referential integrity cannot be removed in Heroku. It suggests considering using another test data scaffolding tool (like FactoryGirl or Fabrication Gem)
Anyway, your code does nothing if the environment is not development. All code is inside the if Rails.env.development?. The first end corresponds to the do. The indentation is wrong. Your code is in fact:
if Rails.env.development?
ActiveRecord::Base.connection.disable_referential_integrity do
end
1.upto(14) do |n|
pic_one = File.open(File.join(Rails.root,'app/assets/images/file1.jpg'))
pic_two = File.open(File.join(Rails.root,'app/assets/images/carpet_2/file2.jpg'))
image = PicAttachment.create!([
{picture: pic_one, w_dream_id: "#{n}"},
{picture: pic_two, w_dream_id: "#{n}"},
])
rug = Product.create!(
pic_attachments: image
if Rails.env.development?
end
end
Ultimately I took this answer, which was already in my code to ensure associations work in development.
For development, this is needed:
ActiveRecord::Base.connection.disable_referential_integrity do
For production:
the disable_referential_integrity isn't allowed in heroku and the problem is the associated model (Pic_Attachment) gets created before the model object it belongs to, hence an error gets thrown because it needs an object to belong. What worked for me was to delete the disable_referential_integrity from the seeds file AND comment out the belongs_to line in the associated model (PicAttachment), then commit/push your changes and it works. (Add these lines back in afterwards so your development works)
I hope this helps someone. Took me a few days of work here.
My Ruby version is ruby 1.9.3p385 . My Rails version is 3.2.12.
I use the following to load the test database:
rake db:seed RAILS_ENV=test
Everything works great. All the Factory Girl stuff is loaded nicely.
Contents of test/factories.rb contains the factories. The contents of db/seeds.rb is simply:
FactoryGirl.create(:music_categorization)
FactoryGirl.create(:dance_categorization)
Now, when I run the tests using the following command:
rake test
Rails deletes all the seed data and the tests fail. I'd like a way to prevent "rake test" from deleting data.
The other route I went was to load the seed data as part of the "rake test" command as mentioned in this question. However, what that ends up doing is loading the test data twice (basically db/seeds.rb is called twice for some reason). I abandoned that route and now simply want to do the following to run my tests:
rake db:seed RAILS_ENV=test
rake test
Any help is appreciated. I basically want to prevent rake test from deleting my data OR figure out a way to not have db/seeds.rb called twice.
AFAIK its not usual to use db:seed to load data for your tests, its normally just used to load seed data for development purposes only.
Instead you should create test data in the actual test file. Usually test data is deleted after each test using something like database_cleaner, so each test starts with an empty database.
For example in rspec you can load test data in a let block, before block or in the test itself, e.g
require 'spec_helper'
describe Page do
let(:user) { FactoryGirl.create(:user) }
before do
# create some data
end
it '#name returns XYZ' do
page = FactoryGirl.create(:page, :user => user)
page.description.should == 'XYZ'
end
it '#description returns ABC' do
page = FactoryGirl.create(:page, :user => user)
page.description.should == 'ABC'
end
end
First, let me just say that in general you should not be using seed data in your tests. Tests are supposed to run with an empty database, and you create only the data you need for each test.
In your case, you seem to have not understood the meaning of the seed data, which is basically core data that your application needs to work properly. If you need to instantiate a couple of models in your tests, simply do (assuming you're using rspec)
before(:each) do
FactoryGirl.create(:music_categorization)
FactoryGirl.create(:dance_categorization)
end
If you still want to run the tests with the seed data, you can always try and run rspec, which will just run all you rspec examples leaving the test database as is. But believe, that's not what you want.
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.
I've been trying to solve a problem for a few weeks now. I am running rspec tests for my Rails app, and they are working fine except for one error that I can't seem get my head around.
I am using MySQL with the InnoDB engine.
I have set config.use_transactional_fixtures = true in spec_helper.rb
I load my test fixtures manually with the command rake spec:db:fixtures:load.
The rspec test is being written for a BackgrounDRb worker, and it is testing that a record can have its state updated (through the state_machine gem).
Here is my problem:
I have a model called Listings. The rspec test calls the update_sold_items method within a file called listing_worker.rb.
This method calls listing.sell for a particular record, which sets the listing record's 'state' column to 'sold'.
So far, this is all working fine, but when the update_sold_items method finishes, my rspec test fails here:
listing = Listing.find_by_listing_id(listing_id)
listing.state.should == "sold"
expected: "sold",
got: "current" (using ==)
I've been trying to track down why the state change is not persisting, but am pretty much lost. Here is the result of some debugging code that I placed in the update_sold_items method during the test:
pp listing.state # => "current"
listing.sell!
listing.save!
pp listing.state # => "sold"
listing.reload
pp listing.state # => "current"
I cannot understand why it saves perfectly fine, but then reverts back to the original record whenever I call reload, or Listing.find etc.
Thanks for reading this, and please ask any questions if I haven't given enough information.
Thanks for your help,
Nathan B
P.S. I don't have a problem creating new records for other classes, and testing those records. It only seems to be a problem when I am updating records that already exist in the database.
I suspect, like nathan, transaction issues. Try putting a Listing.connection.execute("COMMIT") right before your first save call to break the transaction and see what changes. That will break you out of the transaction so any additional rollback calls will be non-effectual.
Additionally, by running a "COMMIT" command, you could pause the test with a debugger and inspect the database from another client to see what's going on.
The other hypothesis, if the transaction experimentation doesn't yield any results, is that perhaps your model really isn't saving to the database. Check your query logs. (Specifically find the update query).
These kind of issues really stink! Good luck!
If you want to investigate what you have in DB while running tests you might find this helpful...
I have a rspec test where I save #user.save and it works like a charm, but then I wanted to see if it's really saved in the DB.
I opened rails console for test environment
rails c test
ran
User.all
and as expected got nothing
I ran my spec that contains:
user_attr_hash = FactoryGirl.attributes_for(:user)
#user = User.new user_attr_hash
#user.save
binding.pry
I thought that stopping the test after save would mean that it's persisted, but that's not the case. It seems that COMMIT on the connection is fired later (I have no idea when:\ )
So, as #Tim Harper suggests, you have to fire that commit yourself in the pry console:
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> User.connection.execute("COMMIT")
Now, if you run User.all in your rails console you should see it ;)