I get an error when I call create on the character factory
factory :user do |f|
f.sequence(:email) { |n| "foo#{n}#example.com" }
f.password "password"
end
factory :character do |f|
f.name "testcharone"
f.race "human"
after(:create) { |character| character.init("fighter")}
association factory: :user
end
Error:
NoMethodError:
undefined method `to_sym' for {:factory=>:user}:Hash
Can anyone see what's wrong?
This test took 16 minutes to complete, while the others, which are similiar took between 5-10 minutes
describe Character do
let(:character) { FactoryGirl.create :character}
describe "#add_units" do
context "when unit doesnt exist beforehand" do
it "it create a new member" do
expect(character.owns.count).to eq(0)
character.add_units("character", "Archer" => 1)
expect(character.owns.count).to eq(1)
expect(character.owns.first.amount).to eq(1)
end
end
In factory :character,
Replace
association factory: :user
With
association :user
You have to pass only the factory name i.e., :user in this case and not a hash factory: :user
You facotry should be as like below
Hope you should ahave a factory for user as well
factory :character do |f|
f.name "testcharone"
f.race "human"
f.association :author, factory: :user
after(:create) { |character| character.init("fighter")}
end
or
factory :character do
name "testcharone"
race "human"
association :user
after(:create) { |character| character.init("fighter")}
end
Related
I m new to factory bot, I try to create a sample data using factory bot but I got this error
How to resolve this error?
features/support/factories.rb:
require 'factory_bot'
FactoryBot.define do
factory :user do
email "xxx123#xyz.co"
password "asdf123"
password_confirmation "asdf123"
end
end
FactoryBot.define do
factory :post do
user = FactoryBot.create(:user)
end
end
require 'factory_bot'
FactoryBot.define do
factory :user do
email "xxx123#xyz.co"
password "asdf123"
password_confirmation "asdf123"
end
end
FactoryBot.define do
factory :post do
user
end
end
as described in FactoryBot documentation
Associations
It's possible to set up associations within factories. If the factory name is the same as the association name, the factory name can be left out.
factory :post do
# ...
author
end
You can also specify a different factory or override attributes:
factory :post do
# ...
association :author, factory: :user, last_name: "Writely"
end
I created factory client and contract. I run test, but display error
FactoryGirl.define do
factory :client, class: User do
role 'client'
first_name 'John'
sequence(:last_name) { |n| "client#{n}" }
sequence(:email) { |n| "client#{n}#example.com" }
# avatar { Rack::Test::UploadedFile.new(File.join(Rails.root, 'public', 'images', '128.jpg')) }
password 'password'
password_confirmation 'password'
end
end
support/controller_macros.rb
module ControllerMacros
def login_client
before do
#client = create(:client)
##request.env['devise.mapping'] = Devise.mappings[:client]
sign_in #client
end
end
end
FactoryGirl.define do
factory :contract do
sequence(:title) { |n| "translation#{n}" }
amount 150
additional_information 'X' * 500
due_date { 21.days.from_now }
association :user, factory: :client
association :user, factory: :contractor
end
end
I run test
rspec spec/controllers/contracts_controller_spec.rb
require 'rails_helper'
describe ContractsController do
login_client
let(:contract) { create(:contract) }
describe 'POST #create' do
context 'with valid attributes' do
it 'redirects to payment page' do
post :create, contract: attributes_for(:contract)
expect(response).to redirect_to payment_new_path
end
end
end
end
Error display:
Failure/Error: post :create, contract: attributes_for(:contract)
FactoryGirl::AttributeDefinitionError:
Attribute already defined: user
What is wrong in factory or test?
Factory :contract defines two attributes named user, which isn't allowed.
Give them unique (within the factory) labels, e.g.:
FactoryGirl.define do
factory :contract do
sequence(:title) { |n| "translation#{n}" }
amount 150
additional_information 'X' * 500
due_date { 21.days.from_now }
association :client, factory: :client
association :contractor, factory: :contractor
end
end
As they seem fitting, I've chosen attribute names corresponding with the factory names. This allows to even shorten this, by leaving out the factory name:
FactoryGirl.define do
factory :contract do
sequence(:title) { |n| "translation#{n}" }
amount 150
additional_information 'X' * 500
due_date { 21.days.from_now }
client
contractor
end
end
(See http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md, section "Associations":
If the factory name is the same as the association name, the factory name can be left out.
)
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 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)) )
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.