I am very new to testing in Rails. I am attempting to create a very basic test for the index action in my albums controller. I am getting an error, not jsut on this test, but on all of my tests. The error looks like this:
bin/rails test test/controllers/albums_controller_test.rb:18
E
Error:
AlbumsControllerTest#test_should_get_edit:
ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraintfailed: users.email: INSERT INTO "users" ("created_at", "updated_at", "id") VALUES ('2017-01-11 21:54:05.906006', '2017-01-11 21:54:05.906006', 298486374)
All of my tests get this error, not just this one. This is the test I was attempting to run with the above example:
require 'test_helper'
class AlbumTest < ActiveSupport::TestCase
test "index action should work" do
get :index
assert_response :success
end
end
Here is the index action in my albums controller:
def index
#albums = Album.all.order(year: :desc).order(title: :asc)
end
Not sure what's going on. Help would be appreciated!
I would need some more code to give a better solution, but by the error it seems that you are trying to create more than one user with the same email. And since you are validating them to be UNIQUE, than the test fails.
So I think the problem must be somewhere else where you create the users for the test.
If you're using fixtures, you can try something like this:
john:
name: $LABEL
email: $LABEL#example.com
And if you are using factory girl, you can try something like this:
factory :user do
name "John"
sequence(:email) { |n| "email#{n}#example.com" }
Hope it helps..
Related
I have a spec testing a model that looks like this:
RSpec.describe SomeModel, type: :model do
subject { described_class.new(test_amount: 99) }
describe 'validates a column' do
it 'does some validations' do
expect(subject).to validate_presence_of(:test_amount)
end
end
end
And a model that looks like this:
class SomeModel < ApplicationRecord
validates :test_amount, presence: true
end
And in the schema it's column looks like this with a not-null set:
t.integer "test_amount", default: 0, null: false
No matter what I do or where I put the code, test_amount is always nil when being tests and errors.
I've tried moving the test lines around, putting the subject in a before etc, but always the
database is throwing a non-null error and even if I raise in the model code
the test_amount value is not 99 it is nil. If I raise the test value in
a before like this:
before do
raise subject.test_amount
end
That does result in a 99, however if I remove this, it is always nil and throws an error when it gets to the expect part of the test.
What am I missing in order to get this test to work, I just cannot seem to get the test_amount to set to 99 when being tested in the actual test step.
The test always throws the error:
PG::NotNullViolation: ERROR: null value in column "test_amount" of relation "some_models" violates not-null constraint or similar, I have but in before-validations to check the value of test_amount and it does not get set.
Thanks for you help, I feel like there's something really basic I'm missing here.
First of all, verify that -
The record is persisted.
Once persisted, then check the attribute value.
Moreover, try moving this line inside the describe block -
subject { described_class.new(test_amount: 99) }
Any chance this is due to not running migrations in the test environment?
bundle exec rake db:prepare RAILS_ENV=test
# or for rack applications
bundle exec rake db:prepare RACK_ENV=test
Other than this I would think that because we aren't saving the record to the database. We wouldn't expect validations to be ran.
As per this documentation we are only expecting to run validations when Record#save or Record#save! has been called.
When running Record#new we are creating a new instance but not saving to our database.
Using the new method, an object can be instantiated without being saved:
When running Record#create we initialize the record and then save this to the database by calling Record#save.
You can write test cases for the presence validation with valid? and errors methods like below:
RSpec.describe SomeModel, type: :model do
subject { described_class.new(test_amount: test_amount) }
describe 'validates a column' do
context 'when valid test_amount'
let(:test_amount) { 99 }
it 'does not throw error' do
expect(subject.valid?).to eq(true)
expect(subject.errors[:test_amount].size).to eq(0)
end
end
context 'when invalid test_amount'
let(:test_amount) { nil }
it 'throws error' do
expect(subject.valid?).to eq(false)
expect(subject.errors[:test_amount].size).to eq(1)
end
end
end
end
I have 2 integrations tests, here how it's look :
class TagFlowTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
setup do
sign_in FactoryGirl.create(:admin)
#partner = create(:partner)
end
test 'can see the list of partners' do
get '/partners'
assert_response :success
assert_select 'tr', 2
end
... more tests below ...
The second test looks the same
The thing is that when a launch rails test on this test, it's working fine. But when I launch :
rails test /test/
I got an error :
UnexpectedError: ActiveRecord::RecordNotUnique: PG::UniqueViolation:
ERROR: duplicate key value violates unique constraint
"index_users_on_email"
I understand that the issue come from
sign_in FactoryGirl.create(:admin)
When I delete this line on the other test, it's working.
But if I do that, I cannot test one test only. How can I do the resolve this ?
UnexpectedError: ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_users_on_email"
So what does this error mean? You have some validation in the model level or the db level which will not let you have the duplicate email for Admin.
So I presume that the factory you used to create Admin, is not creating unique email addresses.
Try this
FactoryGirl.define do
factory :admin do
# your code
email { Faker::Internet.email }
end
end
But this thing requires faker gem. If you don't want to use a gem just for this, try using sequences in factory girl.
Also it's good to have the database in a clean state, when running tests. Consider using https://github.com/DatabaseCleaner/database_cleaner
I'm getting errors like this:
Failure/Error: let(:slide) { build :slide }
ActiveRecord::StatementInvalid:
PG::UndefinedTable: ERROR: relation "albums" does not exist at character 13
: INSERT INTO "albums" ("created_at", "name", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id"
in some random way - sometimes all passes successfully and sometimes some of them don't. I'm getting those usually for same set of tests but when I run only them then I can't reproduce the problem.
I just moved to Postgres as I started to use gem devise and gem apartment for multi-tenancy which works best with schemas. Since then I added to my tests around hook to simulate user login:
given(:user) { create :user }
around :each do |scenario|
login_and_switch_schema user
scenario.run
destroy_users_schema user
destroy_user user
end
all above helpers are defined at spec/support/auth_helpers.rb.
I'm not sure what else is important to dig into it so I just made a commit to github here.
I'm testing it with:
rake db:test:prepare && rspec -X ./spec/models/ ./spec/controllers/ ./spec/features/
(turning off spork doesn't help).
Any ideas ? I feel dizzy looking at it without a clue what to do. Thanks in advance.
UPDATE:
I don't get those errors anymore after changing around hook for every spec file to:
before(:all) do
#user = create :user
end
after(:all) do
destroy_users_schema #user
destroy_user #user
end
before(:each) do
login_and_switch_schema #user
end
at the same time it works twice as fast. Anyway this is more like a workaround as root cause still stays as puzzle for me.
I have an application running in rails 4.1 using mongoid as the orm. I created a model called User which has an attribute email. I am using RSpec for tests. I created the following spec
require 'spec_helper'
describe 'User' do
before(:each) do
#attr = {
user: {
email: "rahul#gmail.com"
}
}
end
it "should create a valid User instance" do
param = ActionController::Parameters.new(#attr)
param.require(:user).permit!
User.create!(param)
end
end
when I run the spec, I get the following error
Failure/Error: User.create!(param)
ActiveModel::ForbiddenAttributesError:
ActiveModel::ForbiddenAttributesError
I know this is related to strong parameters but couldn't figure out what I am doing wrong.
From the fine manual:
require(key)
[...] returns the parameter at the given key [...]
So saying param.require(:user) does nothing at all to param, it merely does an existence check and returns param[:user].
I think you want to say something more like this:
param = ActionController::Parameters.new(#attr)
User.create!(param.require(:user).permit!)
That usage would match the usual:
def some_controller_method
#user = User.create(user_param)
end
def user_param
param.require(:user).permit!
end
usage in controllers.
I'm writing an app with Rails 3. In my functional test, test/functional/cust_infos_controller_test.rb, I have these:
require 'test_helper'
class CustInfosControllerTest < ActionController::TestCase
# Replace this with your real tests.
test "should get cust" do
get :customerinfo
assert_response :success
assert_not_nil assigns("cust_infos")
end
end
My controller is fairly straightforward as it just finds all the customer's info:
class CustInfosController < ApplicationController
def customerinfo
#cust_info = CustInfo.find(:all, :order=>"cust_id")
#cust_info.each do |ci|
if ci.upload_freq == 'W'
ci.upload_freq = 'Weekly'
elsif ci.upload_freq == 'M'
ci.upload_freq = 'Monthly'
end
end
end
end
When I ran it with:
$ ruby -Itest test/functional/cust_infos_controller_test.rb
I got the following error:
Loaded suite test/functional/cust_infos_controller_test
Started
E
Finished in 0.025258 seconds.
1) Error:
test_should_get_cust(CustInfosControllerTest):
ActiveRecord::StatementInvalid: PGError: ERROR: numeric field overflow
DETAIL: A field with precision 4, scale 0 must round to an absolute value less than 10^4.
: INSERT INTO "cust_infos" ("cust_id") VALUES (298486374)
1 tests, 0 assertions, 0 failures, 1 errors
In my cust_infos table, I have cust_id as integer. But I don't know why when I ran controller test to just get some record, active record will execute insert statement. How do I fix this?
UPDATE: I commented out all the lines in customerinfo method, and run the same test. Got the exact same result. So I'm guessing it's not my methods behavior, but rather Rails? Any hint?
I see what you are trying to do. What you need to do is create a helper for your view.
application_helper.rb
def display_upload_freq(s)
case s
when 'W'
'Weekly'
when 'M'
'Monthly'
end
end
cust_info_controller.rb
class CustInfosController < ApplicationController
def customerinfo
#cust_info = CustInfo.find(:all, :order=>"cust_id")
end
end
Then in your view when your are iterating through #cust_info, for upload_freq, use dislay_upload_freq(ci.upload_freq). Assuming you have #cust_info.each do |ci|. Then you won't be confusing the db with saving anything.
Are you using factories or fixtures to create your test data? If not, how are you creating it? My guess is that the insert is happening when your test data is being set up, not because of anything happening in your controller. The second part of that guess is borne out by the fact that commenting out all code in your controller isn't getting rid of the error.
I know this post is quite old, but I will post my answer in case someone is brought here by search engines.
I had the exact same problem, the issue originates from the fixture file(s) in test/fixtures/{name_of_your_model}.yml. Rails adds some initial values in this file, in my case it looked like this:
one: {}
# column: value
#
two: {}
# column: value
and when you want to run the test, it will try to create the test database using this fixtures. And that's where the issue occurs. Trying to create an empty record while you did not allow a null ID in your table.
Deleting these fixtures, or filling them with appropriate values should solve the problem.