I have 2 models - User and Teacher. Teacher belongs_to User, User has Teacher.
So, i use Factory girl gem:
Factory.define :user do |user|
user.user_login "Another User"
user.user_role "admin"
user.password "foobar"
end
Factory.sequence :user_login do |n|
"person-#{n}"
end
Factory.define :teacher do |teacher|
...
teacher.user
end
I met problem and i don't understand how to solve that. When i create user via factory i can easily write:
#user = Factory( :user, :user_login => Factory.next(:user_login) )
And this creates user with inique login.
How can i do same thing for teacher? I tried that:
#teacher = Factory( :teacher, :user_login => Factory.next(:user_login) )
And it doesn't work.
You don't have to specify sequences separately and then pass them to another factory - you can use them inside factories like this:
Factory.define :user do |user|
# ...
user.sequence(:user_login) { |n| "person=#{n}" }
end
or shorter
Factory.define :user do
# ...
sequence(:user_login) { |n| "person=#{n}" }
end
Then, to association a user with teacher:
Factory.define :teacher do
association :user
end
Then you can just call
#teacher = Factory(:teacher)
which will automatically create the associated user with the next user_login in the sequence.
I solved that.
#teacher = Factory( :teacher,
:user => Factory(:user, :user_login => Factory.next(:user_login)) )
Related
In my application an account can have a single owner (user) and multiple users.
In my tests I do this:
# account_factory_static.rb
FactoryGirl.define do
factory :account do
name 'demoaccount'
association :owner, :factory => :user
end
end
# user_factory_static.rb
FactoryGirl.define do
factory :user do
email 'demo#example.com'
first_name 'Jon'
last_name 'Doe'
password 'password'
end
end
and use them like below:
let(:account) { FactoryGirl.create(:account) }
The problem is that right nowaccount.users.count equals 0 because I have no way to do something like #account.users << #account.owner like I do in my controllers when a user signs up.
The question is how can I add the associated account's id to the account_id attribute of the user in FactoryGirl?
In other words how do you do it in FactoryGirl?
Thanks.
You can use after :create block for it:
FactoryGirl.define do
factory :account do
name 'demoaccount'
association :owner, :factory => :user
after :create do |account|
account.users << account.owner
end
end
end
I am using FactoryGirl in my rails application. I have following code snippet
FactoryGirl.define do
factory :pub_company, :class => Company do |c|
c.name "Dixons Group"
c.address "1500 Martin Ave"
c.city "Santa Clara"
c.state "CA"
end
end
FactoryGirl.buid(:pub_company)
Above code can creates a record fine. I am trying to create more data as similar to above one. so, i am using
require 'factory_girl_rails'
FactoryGirl.define do
factory :new do
FactoryGirl.create(:pub_company)
FactoryGirl.create(:adv_user)
FactoryGirl.create(:adv_setting)
FactoryGirl.create(:adv_ad)
end
end
it fails for me. Is this possible using factorygirl to call a different factory and create a record?
Since, the FactoryGirl is used mostly for testing models, I show the sample models, and factories, spec for the new model.
app/models/new.rb
class New < ActiveRecord::Base
attr_protected :company_id
belongs_to :company
end
app/models/company.rb
class Company < ActiveRecord::Base
attr_accessible :name, :address, :city, :state
has_many :news
end
spec/factories/company_factory.rb
FactoryGirl.define do
factory :company do |c|
c.name "Dixons Group"
c.address "1500 Martin Ave"
c.city "Santa Clara"
c.state "CA"
end
end
spec/factories/new_factory.rb
FactoryGirl.define do
factory :new do
company { FactoryGirl.create :company }
# adv_user { FactoryGirl.create :adv_user }
# adv_setting { FactoryGirl.create :adv_setting }
# adv_ad { FactoryGirl.create :adv_ad }
end
end
NOTE: You shell to have adv_user, adv_setting, adv_ad defined also.
spec/models/new_spec.rb
describe New do
it 'Test new model' do
new_instance = FactoryGirl.create :new
new_instance.pub_company.name.should == "Dixons Group"
...
end
end
I want create a factory for a Relationship model which contains two attributes followed_id and follower_id but i have no idea how to do this, this is my factories file :
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
end
factory :relationship do
# i need something like this
# followed_id a_user.id
# follower_id another_user.id
end
end
update
what i want to do with this relationship factory is to test that if i destroy a user, all his relationships will be destroyed too, this is my test :
describe "relationships associations" do
let!(:relationship) { FactoryGirl.create(:relationship) }
it "should destroy associated relationships" do
relationships = #user.relationships.to_a
#user.destroy
expect(relationships).not_to be_empty
relationships.each do |relationship|
expect(Relationships.where(id: relationship.id)).to be_empty
end
end
end
In my experience such "relationship" factory is rarely needed in test. Instead, "user_with_followers" and "user_following_some_ones" are often used.
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :user_with_followers do
ignore do
followers_count 5
end
after_create do |user, evaluator|
followers = FactoryGirl.create_list(:user, evaluator.followers_count)
followers.each do |follower|
follower.follow(user) # Suppose you have a "follow()" method in User
end
end
factory :user_following_some_ones do
# Do the similar
end
end
# Use
FactoryGirl.create :user_with_followers
use association
factory :relationship do |r| # 'r' is how you call relationship in the block
...
r.association :followed #relationship is associated with followed user
#(i'm not sure how your application is set up,
#so you'll have to do this as best makes sense.
#is followed an attribute of user?
#then it would look like `r.association :user`
f.association :follower #same here
end
In the more recent versions of FactoryGirl, you should be able to do this:
factory :relationship do
association :followed, :factory => :user
association :follower, :factory => :user
end
What each of those two association lines does is set up a user instance (using your :user factory), and then assign to followed or follower of the current relationship instance.
Note that you need to specify the factory unless the association name and factory name are the same.
Update:
When creating the Relationship, specify :followed or :follower (whichever is applicable to you). Otherwise, it creates new user records for each of those and uses them.
FactoryGirl.create(:relationship, :followed => #user)
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.
I'm using Factory Girl/Rspec2/Rails 3.
In factories.rb, I have:
Factory.define :user do |user|
user.name 'Some guy'
user.email 'some_guy#somewhere.org'
user.password 'password'
end
Factory.define :org_admin, :parent => :user do |user|
user.email 'org_admin#somehwere.org'
end
Factory.define :user_with_membership_request, :parent => :user do |user|
user.email 'user_with_membership_request#somehwere.org'
end
Factory.define :organization do |org|
org.name 'MEC'
org.description 'Mountain Equipment Co-op'
end
Factory.define :membership do |membership|
membership.user { Factory(:user) }
membership.organization { Factory(:organization) }
end
Factory.define :admin_membership, :parent => :membership do |membership|
membership.user { Factory(:org_admin) }
membership.is_admin true
membership.status 'active'
end
Factory.define :membership_request, :parent => :membership do |membership|
membership.user { Factory(:user_with_membership_request) }
membership.status 'requested'
end
and then in my rspec test I have:
it 'should accept the membership request' do
#org_admin = Factory(:org_admin)
test_sign_in(#org_admin)
#organization = Factory(:organization)
#membership_request = Factory(:membership_request)
put :update, :organization_id => #organization.id, :id => #membership_request.id, :acceptance => 'approve'
...
end
When I run the test, I get:
Failure/Error: #membership_request = Factory(:membership_request)
Validation failed: Name has already been taken
I understand the reason for the failure is because FactoryGirl is creating another organization (with the same name).
But what I'd like to do is create several memberships all associated with the same organization. How do I do that?
Thanks.
Sean
You could check for an existing organization and use it, or create one if none exists:
Factory.define :membership do |membership|
membership.user { Factory(:user) }
membership.organization { Organization.first || Factory(:organization) }
end
FactoryGirl 4+ update:
Factory.define do
factory :membership do
user { create(:user) }
organization { Organization.first || create(:organization) }
end
end
Another approach is to use unique identifiers (e.g.: names) for each factory that you want to reuse, then use initialize_with to generate it:
factory :organization_1 do
ignore { organization_name 'Sample Organization 1' }
name { organization_name }
initialize_with { Organization.find_or_create_by_name(organization_name) }
end
Now any reference to :organization_1 will always retrieve the same Organization. Obviously, you must use distinct names for this to work.
There are two things.
1. You might still want to create unique names for Factory(:organisation) you can achieve that using Factory.sequence which will generate it uniquely for you.
2. You can pass in a Factory(:membership_request, :organization => #organization) to use the existing object instead of creating a new one.
With mongoid you can take combine the use of the #find_or_create_by method with Factory.attributes_for and do something like this
factory :membership do
organization { Organization.find_or_create_by(Factory.attributes_for(:organization))}
end
I'm sure ActiveRecord has something similar.