rspec with factory girl - ruby-on-rails

I have the following factories:
Factory.define :producer, :class => User do |f|
f.sequence(:email) { |n| "producer_#{n}#shit.com" }
f.password "foobar"
f.password_confirmation "foobar"
f.role "producer"
end
Factory.define :business do |f|
f.sequence(:name) { |n| "business_#{n}" }
f.association(:producer, :factory => :producer)
end
Factory.define :deal do |d|
d.sequence(:title) { |n| "deal_#{n}" }
d.sequence(:desc) { |n| "deal_desc_#{n}" }
d.cap "50"
d.rate "2"
d.start Date.today - 1 # This is the date where you put in db
d.end Date.today + 7
d.association :business
end
now when I do the following:
before(:each) do
#consumer = test_sign_in(Factory(:consumer))
#deal = Factory(:deal)
end
I am getting an error:
Failure/Error: #deal = Factory(:deal)
NoMethodError:
undefined method `producer=' for #<Business:0x007fb494290090>
# ./deals_controller_spec.rb:15:in `block (4 levels) in <top (required)>
(Line 15 refers to #deal = Factory(:deal) )
Does anyone know why? I am very new to factory girl and I can't seem to find the documentation explaining association and sequence very well.

The problem here is obviously linked to the creation of your producer association.
Since you're using the old dsl, I'd suggest two solutions:
Factory.define :business do |f|
f.sequence(:name) { |n| "business_#{n}" }
#try this:
f.association(:user, :factory => :producer)
#or this:
f.after_build { |biz| biz.user = Factory.build(:producer) }
end
The use of after_build or after_create is really a matter of choice, depending on your tests purposes.
Here is a link to the new dsl lookup.

Related

shoulda factory girl error Couldn't find model without an ID

Good day, i get this error from
ActiveRecord::RecordNotFound:
Couldn't find User without an ID
my model
has_many :objects, class_name: 'OrderObject', dependent: :destroy
belongs_to :user
belongs_to :tariff
validates :client, :phone, :tariff_id, :days, :user_id, presence: true
spec
before do
user = FactoryGirl.create(:user)
FactoryGirl.create(:order, user_id: user.id)
end
context "validations" do
it { should validate_presence_of :client }
it { should validate_presence_of :phone }
it { should validate_presence_of :tariff_id }
it { should validate_presence_of :days }
end
it { should have_many(:objects) }
it { should belong_to(:tariff) }
it { should belong_to(:user) }
factory
factory :order do
client "MyString"
phone "MyString"
tariff_id 1
days 1
# advt_payed_day 1
# firm_payed_day 1
user_id 1
end
UPDATE 1
changed to
before(:all) do
user = FactoryGirl.create(:user )
puts user.id
order = FactoryGirl.create(:order, user_id: user.id )
puts order.id
end
output
Order
45
32
should have many objects
should belong to tariff
should belong to user
validations
should require client to be set (FAILED - 1)
should require phone to be set (FAILED - 2)
should require tariff_id to be set (FAILED - 3)
should require days to be set (FAILED - 4)
should require user_id to be set (FAILED - 5)
so order & user are created...
Update 2
as Rubyman suggested, i've changed couple of things:
in spec
before(:all) do
user = FactoryGirl.create(:user )
#puts user.id
order = FactoryGirl.create(:order, user_id: user.id )
puts order
puts order.user_id
end
in the factory
factory :order do
client "MyString"
phone "MyString"
tariff_id 1
days 1
# user_id 1
association :user, factory: :user
end
and output is:
Order
#<Order:0x00000005a866a0>
46
should have many objects
should belong to tariff
should belong to user
validations
should require client to be set (FAILED - 1)
should require phone to be set (FAILED - 2)
should require tariff_id to be set (FAILED - 3)
should require days to be set (FAILED - 4)
should require user_id to be set (FAILED - 5)
1) Order validations
Failure/Error: it { should validate_presence_of :client }
ActiveRecord::RecordNotFound:
Couldn't find User without an ID
# ./app/models/order.rb:35:in `user_is_not_admin?'
# ./spec/models/order_spec.rb:14:in `block (3 levels) in <top (required)>'
update 3
after reading advice from tdgs here are the changes:
in model no changes :
validates :client, :phone, :tariff_id, :days, :user_id, presence: true
in spec
describe Order do
before(:each) do
user = FactoryGirl.create(:user )
#puts user.id
order = FactoryGirl.create(:order, user_id: user.id )
puts order
puts order.user_id
puts order.tariff_id
puts order.phone
puts order.days
puts order.client
puts '*****'
user = User.find(order.user_id)
puts user.login
end
context "validations" do
it { should validate_presence_of :client }
it { should validate_presence_of :phone }
it { should validate_presence_of :tariff_id }
it { should validate_presence_of :days }
it { should validate_presence_of :user_id }
end
it { should have_many(:objects) }
it { should belong_to(:tariff) }
it { should belong_to(:user) }
end
output:
#<Order:0x00000006c10ce0>
161
101
MyString
1
MyString
*****
user__7
should require days to be set (FAILED - 1)
output for every should is valid as far as i see...
UPDATE N
should have written it in the beginning. i've run (hoped that it'll solve this issue) in console
bundle exec rake db:migrate
bundle exec rake db:migrate:reset db:test:prepare
First, your factory definition is not defining associations correctly. You should have something like this:
FactoryGirl.define do
factory :user do
sequence(:username) {|n| "username_#{n}"}
# more attributes here
end
factory :tariff do
# attributes
end
factory :order do
client "MyString"
phone "MyString"
tariff
user
days 1
end
end
Then your tests should be written like this:
context "validations" do
it { should validate_presence_of :client }
it { should validate_presence_of :phone }
it { should validate_presence_of :tariff_id }
it { should validate_presence_of :days }
end
it { should have_many(:objects) }
it { should belong_to(:tariff) }
it { should belong_to(:user) }
All the code you currently have in the before filter is not relevant right now. Also notice that using before(:all) might have some strange effects when running your tests, because they do not run inside a transaction. before(:each) on the other hand does.
try this
before {
#user = FactoryGirl.create(:user, :email => "test.com", :password => "test123", ... )
#order = FactoryGirl.create(:order, :user_id => #user.id )
}
Factory
require 'factory_girl'
FactoryGirl.define do
factory :order do
client "MyString"
...
...
end
end
Check how to create associations with factory girl
https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md
i moved away from shoulda and rewrote checks for validation. This way it works:
before(:each) do
#user = FactoryGirl.create(:user )
#order = FactoryGirl.create(:order, user_id: #user.id )
end
it 'absence of client isn\'t acceptable' do
temp = #order.client
#order.client = ''
#order.should_not be_valid
#order.client = temp
#order.should be_valid
end

How can I force Forgery to return unqiue data within a Factory_girl definition

My factory looks like this:
Factory.define :coupon do |c|
c.title { Forgery(:lorem_ipsum).sentences(3, :random => true) }
end
And my call from Rspec looks like this:
coupons = []
5.times {|i| coupons << Factory(:coupon, :starts_at => i.days.ago) }
With my Coupon model I have a validation with requires the title to be unique. The only way I am able to run this test is by doing this in my factory:
Factory.define :coupon do |c|
c.title {|i| Forgery(:lorem_ipsum).sentences(3, :random => true) + "#{i}" }
end
Surely there must be a better way?
This is how I would do it (using the new Factory Girl syntax):
FactoryGirl.define do
factory :coupon do
sequence(:title) { |n| Forgery::LoremIpsum.words(n, :random => true) }
sequence(:starts_at) { |n| n.days.ago }
end
end
Then creating coupons in a spec:
coupons = FactoryGirl.create_list(:coupon, 5)

Declare :child_key for has_many associations in factory_girl (datamapper)

I use datamapper and postgres for my ror application, in my models i have such associations:
#/models/account.rb
has n, :transfers_out, "Transfer", :child_key => [ :account_from_id ]
has n, :transfers_in, "Transfer", :child_key => [ :account_to_id ]
#/models/transfer.rb
belongs_to :account_from, "Account", :child_key => [:account_from_id], :required => true
belongs_to :account_to, "Account", :child_key => [:account_to_id], :required => false
Now i need to test in rspec by using factory girl. So, I've wrote this:
#/factories/account.rb
Factory.define :account do |f|
f.transfers_out {|transfer| [transfer.association(:transfer)]}
f.transfers_in {|transfer| [transfer.association(:transfer)]}
f.amount "0"
end
Factory.define :account_big, :class => :account do |f|
f.name "MyMillionDollarPresent"
f.amount "10000"
end
Factory.define :account_small, :class => :account do |f|
f.name "PoorHomo"
f.amount "100"
end
and little transfer factory
Factory.define :transfer do |f|
f.id "1"
f.comment "payment"
f.status "proposed"
f.amount "0"
end
So, I've tried to test creation of transfer from account:
describe Transfer do
before(:each) do
#account_big = Factory(:account_big)
#account_small = Factory(:account_small)
#transfer = Factory(:transfer)
end
it "should debit buyer" do
#buyer = #account_big
#buyer.transfers_out = #transfer
#transfer.amount = 3000
#buyer.amount -= #transfer.amount
#buyer.amount.should == 7000
end
But that results me with failed test:
1) Transfer should debit buyer
Failure/Error: #buyer.transfers_out = #transfer
TypeError:
can't convert Transfer into Array
# ./spec/models/transfer_spec.rb:15:in `block (2 levels) in <top (required)>'
Soo, what should i do and how should i declare the association with the child key in this situation? Would be thankful for any help.
#buyer.transfers_out is an array and #transfer is a single object. If you want to make an array with one element you should use #buyer.transfers_out = [ #transfer ] or something like #buyer.transfers_out << #transfer.

Factory Girl - Why are Records being continually created?

I'm new to factory girl. What I'm trying to do is create 2 users, which belong to a group, joined by the permission model. Here's what I have. When I run this one rspec, it creates more than 2 users, 4+. Why? thanks
factories.rb:
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 "xxxxxxxx"
end
Factory.define :group do |f|
f.association :user
f.sequence(:name) { |n| "myGroup#{n}" }
f.sequence(:private_email) { |n| "myGroup#{n}" }
end
Factory.define :permission do |f|
f.role_id 1
f.user {|i| i.association(:user)}
f.group {|i| i.association(:group)}
f.creator_id {|i| i.association(:user).id}
end
incoming_mails_controller_spec.rb:
describe IncomingMailsController do
include Devise::TestHelpers
before do
#user = Factory.create(:user, :permissions => [Factory.create(:permission)])
#user2 = Factory.create(:user, :permissions => [Factory.create(:permission)])
#group = Factory(:group)
end
it "should create a new IncomingMail record in the db" do
....
end
....
This is because Factory.create(:user...) creates 1 one user (you have two of these, so thats two users right there). And creating two new Factory.create(:permissions) also creates a user by the rules you set up in your define(your associations), thus equaling 4.
If you wanted to to only create two users here, you could do
#user = Factory.create(:user)
#user1 = Factory.create(:user)
#perm1 = Factory.create(:permission, :user => #user)
#perm2 = Factory.create(:permission, :user => #user1)

rspec if giving a NoMethodError for Updating a User.field

Why does:
User.stuff_to_extract = 'boo'
work in the rails c
But in rspec it fails with this:
Failure/Error: #user1.stuff_to_extract = 'XXXXXX'
NoMethodError:
undefined method `stuff_to_extract=' for #<User:0x105cd4e60>
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 "xxxxxxx"
f.email_signature_to_extract ""
end
In the first case you are calling the method on the User class. In the second you are calling it on a User instance. To fix the second example use:
User.stuff_to_extract = 'XXXXXX'
or redefine your function to be available to the instance:
class User
def stuff_to_extract= stuff
...
end
end
instead of being available to the class:
class User
def self.stuff_to_extract= stuff
...
end
end

Resources