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
Related
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..
I met a very strange issue when writing test using RSpec. Assume that I have 2 models: Company and Item with association company has_many items. I also set up database_cleaner with strategy transaction. My RSpec version is 2.13.0, database_cleaner version is 1.0.1, rails version is 3.2.15, factory_girl version is 4.2.0. Here is my test:
let(:company) { RSpec.configuration.company }
context "has accounts" do
it "returns true" do
company.items << FactoryGirl.create(:item)
company.items.count.should > 0
end
end
context "does not have accounts" do
it "returns false" do
company.items.count.should == 0
end
end
end
I set up an initial company to rspec configuration for using in every test because I don't want to recreate it in every tests because creating a company takes a lot of time(due to its callbacks and validations). The second test fails because item is not cleaned from the database after the first test. I don't understand why. If I change line company.items << FactoryGirl.create(:item) to FactoryGirl.create(:item, company: company), the it passes. So can any body explain for me why transaction isn't rollbacked in the first situation. I'm really messed up
Thanks. I really appreciate.
I think the problem is not in the rollback and I'm wondering if company.items can store it's value between contexts but I'm not sure.
I'm unable to reproduce it quickly so I want to ask you to:
check log/test.log when the rollback is performed
how many INSERTs was made for company.items << FactoryGirl.create(:item)
than change on the first test > to < that way: company.items.count.should < 0 it'll make test to fail but you'll get count value. Is it 1 or 2 ?
If you have relation between Company and Item model like has_many/belongs_to than I would suggest to just use build(:item) which should create company for it as well:
for example:
let(:item) { FactoryGirl.build(:item) }
context "has accounts"
it "returns true" do
item.save
Company.items.count.should == 1
end
don't forget to include association :company line at :item's factory
Hint:
add to spec_helper.rb:
RSpec.configure do |config|
# most omitted
config.include FactoryGirl::Syntax::Methods
and you can call any FactoryGirl method directly like this:
let(:item) { build(:item) }
I'm trying to test PG database constraints in a rails 4 using RSpec, and I'm not sure how to set it up.
My thought was to do something like this:
before do
#subscriber = Marketing::Subscriber.new(email: "subscriber#example.com")
end
describe "when email address is already taken" do
before do
subscriber_with_same_email = #subscriber.dup
subscriber_with_same_email.email = #subscriber.email.upcase
subscriber_with_same_email.save
end
it "should raise db error when validation is skipped" do
expect(#subscriber.save!(validate: false)).to raise_error
end
end
When I run this, it does in generate an error:
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint
However, the test still fails.
Is there a proper syntax to get the test to pass?
Try
it "should raise db error when validation is skipped" do
expect { #subscriber.save!(validate: false) }.to raise_error
end
For more information, check the more info on rspec-expectations expect-error matchers
Hope this helps!
Slight modification to #strivedi183's answer:
it "should raise db error when validation is skipped" do
expect { #subscriber.save!(validate: false) }.to raise_error(ActiveRecord::RecordNotUnique)
end
The justification for being more verbose with the error class is that it protects you from having other possible checks that may raise an error that are not related to specific duplication error you wish to raise.
For example:
I run a test and all asserts pass, but I run the test again, and in my case, I receive the following error:
Validation failed: Email has already been taken
It seems adding: sequence(:email) {|n| "nobody#{n}#xyz.com" } for factorygirl is pointless
The tests seem to pass sometimes and others fail for errors reasons like these.
Please advise on the problem/solution.
try deleting all the records from tables before running test case.
eg:-
describe User do
before(:each) do
User.delete_all
end
it "validate e-mail" do
(do staff..)
end
end
I´m not sure it is a definitive solution, but i added random numbers to my product references on the factories with factorygirl using the lazy attributes.
Example:
FactoryGirl.define do
factory :product do
reference {"AB"+rand(999).to_s}
description "Test Product"
quantity {(1..9999).to_a.sample}
price_per_unit {((1..999999).to_a.sample)/100.to_f}
end
end
Do you have any "before(:all)" block? maybe you are missing the corresponding "after(:all)" to clean the data. before(:each) acts as a transaction so the database gets cleaned, before(:all) works like a normal query, yout have to handle the cleanup in an after(:all) block.
I am using Ruby on Rails 3.0.10, RSpec 2 and FactoryGirl. I am trying to validate user account data.
In my model I have:
class Users::Account < ActiveRecord::Base
...
def get_account_password_salt(password)
make_user_account_password_salt(password)
end
end
In my spec file I have
it "should have a valid password salt" do
users_account.password_salt.should == Users::Account.get_account_password_salt('123456')
end
When I run the rspec command I get the following error:
Users::Account should have a valid password salt
Failure/Error: users_account.password_salt.should == Users::Account.get_account_password_salt('123456')
NoMethodError:
undefined method `get_account_password_salt' for #<Class:0x0000010729c9f0>
What is the problem and how can I solve that?
I also tryed to use ::Users::Account.get_account_password_salt('123456') (note the :: at the beginning) but it still doesn't work.
SOLUTION
The problem was that I have to run
users_account.get_account_password_salt('123456')
instead of:
Users::Account.get_account_password_salt('123456')