Seems like I should have been able to find an obvious answer to this problem after a few hours of Googling and testing.
I want to be able to set caredate.user_id => provider.user_id within the caredate factory.
Test Error:
ActiveRecord::RecordInvalid:
Validation failed: User must be same
as provider user
I have an ActiveRecord validation which works when tested via the browser:
class Caredate < ActiveRecord::Base //works fine when testing via browser
belongs_to :user
belongs_to :provider
validates_presence_of :user_id
validates_presence_of :provider_id
validate :user_must_be_same_as_provider_user
def user_must_be_same_as_provider_user
errors.add(:user_id, "must be same as provider user") unless self.user_id == self.provider.user_id
end
end
//factories.rb
Factory.define :user do |f|
f.password "test1234"
f.sequence(:email) { |n| "foo#{n}#example.com" }
end
Factory.define :caredate do |f|
f.association :provider
**f.user_id { Provider.find_by_id(provider_id).user_id } //FAILS HERE**
end
Factory.define :provider do |f|
f.association :user
end
My apologies if this has been answered previously; I tried several different options and couldn't get it to work.
Update: This passes validation, so I'm getting closer. I could hack with a random number.
Factory.define :caredate do |f|
f.association :user, :id => 779
f.association :provider, :user_id => 779
end
Factory.define :caredate do |f|
provider = Factory.create(:provider)
f.provider provider
f.user provider.user
end
Try setting the user_id in after_create or after_build:
Factory.define :caredate do |f|
f.after_create { |caredate| caredate.user_id = caredate.provider.user_id }
end
Related
I'm trying hard to cover all of my model's methods, associations and validation in my unit tests and so far it's going great. I've subscribed to TreeHouse and watched Ruby Foundations - Testing religiously.
I stumbled last night on this error while testing a method for my Provider.rb model:
class Provider < ActiveRecord::Base
attr_accessible :description, :name
validates :name, :presence => true
validates :description, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :length => { :minimum => 6, :maximum => 100 }
has_many :courses
resourcify
def unique_locations
Location.joins(sessions: :course).where(courses: { provider_id: self.id }).uniq.pluck('locations.name')
end
end
My unit test for the unique_locations method is the following:
test 'should return a list of unique locations' do
provider = FactoryGirl.build(:provider)
assert_equal provider.unique_locations, ["location_1", "location_2"]
end
I get the following error after running my tests:
<[]> expected but was
<["location_1", "location_2"]>.
My factories are quite simple:
FactoryGirl.define do
factory :course do
name 'Snowboard 101'
description 'Snowboard course'
association :provider, factory: :provider
end
end
FactoryGirl.define do
factory :provider do
name 'The School of Hard Knocks'
description 'School description'
end
end
FactoryGirl.define do
factory :session_snowboard, class: Session do
name 'Winter Session'
description 'Snowboarding 101'
price 200
class_size 4
association :course, factory: :course
association :location, factory: :location_1
end
factory :session_ski, class: Session do
name 'skiing 101'
description 'Start in november'
price 100
class_size 4
association :course, factory: :course
association :location, factory: :location_2
end
end
FactoryGirl.define do
factory :location_1 do
name 'location_1'
end
factory :location_2 do
name 'location_2'
end
end
My unique_locations method works fine in my different environment. I just can't figure out why it's not returning the list of unique locations in test.
Any idea?
Thanks,
Francis
You are calling FactoryGirl.build(:provider) which only builds and doesn't save to the DB, so the unique_locations obviously wouldn't have the id to go by. Use create and it should fine.
So after much poking around with Factory_Girl I found the solution:
Here are my factories:
FactoryGirl.define do
factory :provider do
name 'McGill University'
description 'McGill is one of the best universities in the world.'
after(:create) {|provider| create_list(:course, 2, provider: provider) }
end
end
FactoryGirl.define do
factory :course do
name 'Snowboard 101'
description 'Snowboard course'
provider
after(:create) {|course| create_list(:session, 2, course: course) }
end
end
FactoryGirl.define do
factory :session do
name 'Winter Session'
description 'Snowboarding 101'
price 150
class_size 4
course
location
end
end
FactoryGirl.define do
factory :location do |l|
l.sequence(:name) { |n| "location_#{n}"}
end
end
I've also updated my test:
test 'should return a list of unique locations' do
provider = create(:provider)
assert_equal provider.unique_locations, %w[location_1 location_2 location_3 location_4]
end
This successfully creates 4 different locations.
I'm new to using RSpec and FactoryGirl. I'm trying to add RSpec tests to an existing codebase.
I have the following factories defined:
Factory.sequence :email do |n|
"somebody#{n}#example.com"
end
Factory.sequence :login do |n|
"inquire#{n}"
end
Factory.define :user do |f|
f.login { Factory.next(:login) }
f.email { Factory.next(:email) }
f.password 'inquire_pass'
f.password_confirmation 'inquire_pass'
f.first_name 'test'
f.last_name 'guy'
f.newsletter true
f.notify_of_events true
f.terms_of_service true
end
Factory.define :project do |project|
project.title "Example Project Title"
project.association :user
project.association :provider
project.association :project_request
project.association :offering
project.association :offering_type
end
When I try to create a Project factory in my tests, however and assign it to #project:
require 'spec_helper'
describe Charge do
before(:each) do
#provider_user = Factory(:user)
#provider = stub_model(Provider, :user => #provider_user)
#user = Factory(:user)
#project_request = stub_model(ProjectRequest)
#project = Factory(:project, :user => #user, :provider => #provider, :offering_fixed_fee_number => 700,
:project_request_id => #project_request.id)
#attr = {
:user_id => #user.id,
:provider_id => #provider.id,
:charge_client => "0.01"
}
#charge = #project.build_charge(#attr)
end
I get an error message when running the tests indicating that the validations for the associated user have failed:
Validation failed: User email can't be blank, User email is too short (minimum is 3 characters), User email does not look like a valid email address., Login can't be blank
The relevant validations on the User model are:
validates_presence_of :login, :email
validates_uniqueness_of :login, :email, :case_sensitive => false
validates_length_of :login, :within => 5..20
validates_format_of :login, :with => /^[a-z0-9-]+$/i, :message => 'may only contain letters, numbers or a hyphen.'
validates_length_of :email, :within => 3..100
validates_format_of :email, :with => Authentication.email_regex, :message => 'does not look like a valid email address.'
I'm able to create valid User factories (by themselves) with no problem. But when I try to create projects that have a User association, and specify the associated User as the factory user I created earlier, the validations on that User fail. Any ideas what I'm missing here?
Thanks very much,
Dean Richardson
Maybe it's because factory param in association method is missing:
Factory.define :project do |project|
project.association :user, :factory => :user
...
end
But in this case it could be written more easily:
Factory.define :project do |project|
project.user
...
end
See Factory Girl. Getting Started
I am having some trouble with factory_girl's associations:
Factory.define :account do |f|
f.sequence(:email) {|n| "john#{n}#example.com" }
f.password "secret"
f.confirmed_at 2.days.ago.to_s(:db)
f.name "John Doe"
f.seller false
f.admin false
end
Factory.define :request do |f|
f.association :account
f.message 'Test message.'
end
And here's the problem:
When I do a = Factory(:request), a.account => nil but when I do a = Factory.build(:request), a.account is correct.
Any idea why this might be ?
Thanks
Factory(:request) calls for default strategy, did you changed that somewhere?
I'm trying to write a validation class in rails 3 that will check for the presence of at least one associated object that has a particular property value.
In my scenario, an Account can have many Users. The User model has a "Role" string field. An account must have at least one User with a Role that equals "admin".
The following code is breaking during my testing (I'm using rspec & Factory Girl). When the tests are executed, the account_id is returning as null.
Here is the model:
class Account < ActiveRecord::Base
validates :name, :presence => true, :uniqueness => true
validate :has_one_admin
has_many :users
attr_accessible :name
private
def has_one_admin
User.where(:role => "admin", :account_id => self.id).count > 0
end
end
Here is the error being thrown by rspec:
Error message being thrown: Failure/Error: #account = Factory(:account_with_admin)
ActiveRecord::StatementInvalid:
SQLite3::SQLException: no such column: users.account_id: SELECT COUNT(*) FROM "users" WHERE "users"."role" = 'admin' AND "users"."account_id" IS NULL
Here is the RSpec test:
require 'spec_helper'
describe Team do
# - Removed -
# before(:each) do
# #account = Factory(:account)
# #attr = { :name => "Testing Team"}
# end
# Modified after discussion...
before(:each) do
#user = Factory(:user)
#act_attr = { :name => "My Account",
:users => #user }
#account = Account.new(#act_attr)
#attr = { :name => "Testing Team"}
end
# End of modification
it "must have a name" do
no_name_team = Team.new(#attr.merge(:name => ""))
no_name_team.should_not be_valid
end ...
And finally, my factory file:
Factory.define :admin, :class => User do |f|
f.email 'admin#admin.com'
f.password 'password'
f.role 'admin'
end
Factory.define :team, :class => Team do |f|
f.name 'Testing Team'
end
Factory.define :account, :class => Account do |f|
f.name 'Testing Account'
end
Factory.define :account_with_admin, :parent => :account do |f|
f.after_create { |a| Factory(:admin, :account => a) }
end
My assumption is that I'm jumping ahead of the persisting of the object somewhere but I'm just not sure where. Thanks for any help / direction!
I have an spec like so:
require 'spec_helper'
describe IncomingMailsController do
include Devise::TestHelpers
before(:each) do
#user = Factory.create(:user)
#user1 = Factory.create(:user)
#group = Factory(:group)
#perm1 = Factory.create(:permission, :user => #user)
#perm2 = Factory.create(:permission, :user => #user1)
end
it "xxxxx case 1" do
....
end
it "xxxxx case 2" do
....
end
The first case 1, works fine but then the 2nd fails with:
Failure/Error: #perm1 = Factory.create(:permission, :user => #user)
RuntimeError:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
# ./spec/factories.rb:23
Does the before each run fresh for each it block?
factories.rb looks like:
require 'factory_girl'
Factory.define :user do |f|
f.sequence(:fname) { |n| "fname#{n}" }
f.sequence(:lname) { |n| "lname#{n}" }
f.sequence(:email) { |n| "email#{n}#google.com" }
f.password "password"
f.password_confirmation { |u| u.password }
f.invitation_code "dmbsrv82811"
end
Factory.define :group do |f|
f.name "myGroup"
f.sequence(:private_email) { |n| "myGroup#{n}" }
end
Factory.define :permission do |f|
f.role_id 1
f.group_id do
(Group.find_by_name('myGroup')).id
end
f.creator_id do
(User.find_by_fname('fname1')).id
end
end
Thanks
On line 23 of factories.rb you have
(User.find_by_fname('fname1')).id
This is hardcoded to find fname1. However, your factory uses a sequence to define fname:
f.sequence(:fname) { |n| "fname#{n}" }
This means that in the second spec, the value for fname will be fname2, not fname1. This is because sequences aren't reset between different specs.
All of this means that when you call User.find_by_fname, it can't find a user with fname1 (only fname2), so it returns nil, which is why you get the called id for nil error.
-- Edit --
Are you doing anything with the user attribute you pass in to the permission factory (for eg with Factory.create(:permission, :user => #user))? If not, I'd change it to something like
Factory.create(:permission, :creator => #user)
Note: if you don't have Permission#creator setup as an association with User you'll need to rather do
Factory.create(:permission, :creator_id => #user.id)
On a similar vein, you might want to define your factory more along the lines of
Factory.define :permission do |f|
f.role_id 1
f.association :group, :factory => :group
f.association :creator, :factory => :user
end
If your associations are setup correctly, there's no need to worry about the ids, the association does the Right Thing for you.