How can I setup and use factory_girl_rails properly? - ruby-on-rails

I think I have a problem with configuring FactoryGirl with rails. I initially followed ASCIIcasts #275: how i test, but rake is giving me NameError: uninitialized constant ...
Am I missing something? Is it possible that some config file are wrong? I'm pretty new to RSpec and Rails.
I'm using Rails 3.2.2 + Mongoid + RSpec + factory_girl_rails.
Error:
Failures:
1) User should save user with valid required fields
Failure/Error: let(:user) { FactoryGirl.build(:valid_user) }
NameError:
uninitialized constant ValidUser
# ./spec/models/user_spec.rb:4:in `block (2 levels) in <top (required)>'
# ./spec/models/user_spec.rb:7:in `block (2 levels) in <top (required)>'
spec/factories.rb
FactoryGirl.define do
factory :valid_user do
name 'somename'
email 'a#b.com'
password 'somepassword'
end
end
spec/models/user_spec.rb
require 'spec_helper'
describe User do
let(:user) { FactoryGirl.build(:valid_user) }
it "should save user with valid required fields" do
user.should be_valid
end
end
spec/spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.infer_base_class_for_anonymous_controllers = false
config.include FactoryGirl::Syntax::Methods
end

It's usually helpful to output the whole error, or at least the whole first sentence -- you haven't even told us what the missing constant is!
UPDATE: Thanks for the whole error. When you define the factory :valid_user, Factory Girl will automatically assume it is for a model named ValidUser. To get around this, you can either name your factory :user (assuming you have a User model), or you can try:
FactoryGirl.define do
factory :valid_user, :class => User do
name 'somename'
email 'a#b.com'
password 'somepassword'
end
end
Alternatively, if you want to have a couple different types of User factories, you can use:
FactoryGirl.define do
factory :user do
# set some attrs
end
factory :valid_user, :parent => :user do
name 'somename'
email 'a#b.com'
password 'somepassword'
end
factory :invalid_user, :parent => :user do
# some other attrs
end
end

You can declare factory like this........
Factory.define :organization do |g|
g.name 'Test Organization'
g.phone_number '5345234561'
g.website_url 'www.testorg.com'
g.city 'chichago '
g.association :state
end
And use it in organization_spec like this.....
require 'spec_helper'
describe Organization do
before :each do
#state = Factory :state
#organization = Factory :organization ,:state => #state
end
it "should be invalid without a name" do
#organization.name = nil
#organization.should_not be_valid
end
end
And enjoy!!!!!!!!!!!!!!!!

Related

RSpec with FactoryGirl explicit subject

I'm using RSpec with FactoryGirl within a Ruby on Rails environment for testing.
I want to specify my factories as follows:
factory :user do
role # stub
factory :resident do
association :role, factory: :resident_role
end
factory :admin do
association :role, factory: :admin_role
end
end
And I'd like to do something like this in my spec:
require 'rails_helper'
RSpec.describe User, type: :model do
context "all users" do
# describe a user
# subject { build(:user) }
# it { is_expected.to be_something_or_do_something }
end
context "residents" do
# describe a resident
# subject { build(:resident) }
# it { is_expected.to be_something_or_do_something }
end
context "admins" do
# describe a admin
# subject { build(:admin) }
# it { is_expected.to be_something_or_do_something }
end
end
Can this be done by explicitly setting the subject? When I do, I keep getting duplicate roles errors.
If anyone has any advice or suggestion, it would be greatly appreciated!
But this causes the user_spec.rb to use the :user factory.
No, it does not. Assuming you configured FactoryGirl correctly, RSpec can use whatever factory you'd like "on demand" in any test file. Configuration-wise, in rails_helper.rb throw this in:
RSpec.configure do |config|
# ...
config.include FactoryGirl::Syntax::Methods
# ...
end
Then, in your spec file:
require 'rails_helper'
RSpec.describe User, type: :model do
context "all users" do
let(:user) { create(:user) }
it 'is a user' do
# Here `user` is going to be a user factory
expect(user.unit).not_to be_present
end
end
context "residents" do
let(:user) { create(:resident) }
it 'is a resident' do
# Here `user` is going to be a resident factory
expect(user.unit).to be_present
end
end
context "admins" do
let(:user) { create(:admin) }
it 'is an admin' do
# Here `user` is going to be an admin factory
expect(user.role).to be('admin_role')
end
end
end
In short, you can use create(<factory_name>) on any factory definition that exists in any one of these paths:
test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb
Note that if you haven't placed the config.include FactoryGirl::Syntax::Methods inside your RSpec.configure, you can still create any factory, by doing FactoryGirl.create(<factory_name>) instead of create(<factory_name>).
I don't think you would want to stop them from auto loading, and I'm not actually sure what your use case is for not allowing them to load?
RSpec automagically fetches the factory for a spec
Rspec loads all the factories into memory when your spec helper loads I believe. Because your using factory inheritence your just loading each of these into memory before your tests run, nothing is being called, no objects are being created or built. They are just ready to use in your tests.
Are you getting a specific error or is there some case I'm not seeing that you need?
I found the solution to my problems here: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations
What I needed to use in my user factories was association :role, factory: :role, strategy: :build

Getting factory not registered (ArgumentError) when trying to run test with rspec and factorygirl

I keep getting Factory not registered: user (ArgumentError)
when I try to run my test files with factory_girl_rails. I read several post about that and tried to follow each of them without any success. In my gemfile I have the gem 'factory_girl_rails':
group :development, :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'annotate'
gem 'better_errors'
gem 'binding_of_caller'
gem 'letter_opener'
gem 'pry-byebug'
gem 'pry-rails'
gem 'quiet_assets'
gem 'spring'
end
I have a spec folder in my project with different folders inside :
controllers, factories, models, lib and support.
In my spec folder I have a spec_helper.rb :
require 'factory_girl_rails'
FactoryGirl.find_definitions
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.include FactoryGirl::Syntax::Methods
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
end
and a rails_helper.rb :
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'devise'
require_relative 'support/controller_macros'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
end
Inside my factories' folder, I have files for each one of my models for instance tournaments.rb :
require 'factory_girl_rails'
FactoryGirl.define do
factory :tournament do |f|
f.user FactoryGirl.create(:user)
f.accepted [true, false].sample
f.amount { Faker::Number.number(2) }
f.starts_on { Faker::Date.between(2.days.ago, Date.today) }
f.ends_on { Faker::Date.forward(23) }
f.address {Faker::Address.street_address}
f.city { Faker::Address.city }
f.name { Faker::Lorem.sentence }
f.club_organisateur { Faker::Company.name }
f.homologation_number {Faker::Company.swedish_organisation_number}
f.postcode { Faker::Address.postcode }
f.young_fare { Faker::Number.number(2) }
f.iban "jjddjjdjdjdjddj"
f.bic "djdjdjdjdjdjdjdjd"
f.club_email { Faker::Internet.email }
f.region "Ile de France"
end
end
Inside controllers folder, I have for instance tournaments_controller_spec.rb that looks like this :
require 'rails_helper'
require 'factory_girl_rails'
require 'spec_helper'
describe TournamentsController do
render_views
login_user
describe "index" do
it "returns a valid html_body" do
get :index
expect(response.body).to include("Il n'y a pas encore de tournoi référencé sur WeTennis")
end
end
describe "show" do
it "returns a valid tournament si le tournament n'est pas fini" do
get :show
expect(response.body).to include("s'inscrire")
end
end
end
and inside models folder for instance tournament_spec.rb :
require 'rails_helper'
require 'factory_girl_rails'
require 'spec_helper'
describe Tournament do
it "has a valid factory" do
FactoryGirl.create(:tournament).should be_valid
end
it "is invalid without a start date" do
FactoryGirl.build(:tournament, start_date: nil).should_not be_valid
end
it "is invalid without a end date" do
FactoryGirl.build(:tournament, end_date: nil).should_not be_valid
end
it "is invalid without a user" do
FactoryGirl.build(:tournament, user: nil).should_not be_valid
end
end
My users factory looks exactly like the others in folder factories (users.rb)
require 'factory_girl_rails'
FactoryGirl.define do
factory :user do |f|
f.first_name { Faker::Name.first_name}
f.last_name { Faker::Name.last_name }
f.password { Faker::Internet.password}
f.licence_number { Faker::Lorem.sentence }
f.email { Faker::Internet.email }
end
end
same for my user_spec.rb inside my models folder :
require 'rails_helper'
require 'factory_girl_rails'
require 'spec_helper'
describe User do
it "has a valid factory" do
FactoryGirl.create(:user).should be_valid
end
it "is invalid without an email" do
FactoryGirl.build(:user, email: nil).should_not be_valid
end
it "is invalid without a password" do
FactoryGirl.build(:user, password: nil).should_not be_valid
end
end
Why am I getting this error ?
I suspect the problem is your use of the user factory in the tournament factory (and maybe others):
factory :tournament do |f|
f.user FactoryGirl.create(:user)
FactoryGirl allows you to created associated objects quite simply (see the relevant section their documentation). To add an associated object which is created by a factory you can just do:
f.user
This will cause FactoryGirl to create a user object using the equivalent of FactoryGirl.create(:user) when a tournament is created.
Note also that you don't need the f. prefix. It should work find without.
The reason that it is causing an error is that the code FactoryGirl.create(:user) is being executed when your tournament factory loads and the user factory hasn't been loaded at that point. For stuff like: region 'Ile de France it doesn't matter because the string can be evaluated fine but for another factory call it does matter because the factory has to be defined already.

Factory still not registered after trying solutions provided

I am trying to write an Rspec test for the first time, my model test worked out fine, but I have problems with my controller test. Which seems weird. For my model test, I'm following the example from: https://gist.github.com/kyletcarlson/6234923
I am given the infamous Factory not registered: error. The log is below:
1) ProductsController POST create when given all good parameters
Failure/Error: post :create, product: attributes_for(valid_product)
ArgumentError:
Factory not registered: #<Product:0x007fc47275a330>
# ./spec/controllers/products_controller_spec.rb:12:in `block (4 levels) in <top (required)>'
I have tried solutions given by others and now my files look like this:
Gemfile
group :test, :development do
gem 'shoulda'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'database_cleaner'
end
rails_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'factory_girl_rails'
...
RSpec.configure do |config|
...
config.include FactoryGirl::Syntax::Methods
end
/spec/factories/products.rb
FactoryGirl.define do
factory :product do
sequence(:name) { |n| "test_name_#{n}" }
price "1.50"
description "Test Description"
end
end
/spec/controllers/products_controller_spec.rb
require 'rails_helper'
describe ProductsController do
let(:valid_product) { create(:product) }
let(:invalid_product) { create(:product, name: nil, price: 0, description: test_description) }
describe "POST create" do
context 'when given all good parameters' do
before(:each){
post :create, product: attributes_for(valid_product)
}
it { expect(assigns(:product)).to be_an_instance_of(Product) }
it { expect(response).to have_http_status 200 }
end
end
end
Any help will be appreciated. Thanks.
*Updated to include factories details, that was already implemented before question was posed.
On this line
post :create, product: attributes_for(valid_product)
You are calling attributes_for passing valid_product which is an actual instance of Product, hence the error message.
I suspect you intended to write
post :create, product: attributes_for(:product)
You need to specify factory separately. Create spec/factories/products.rb with content:
FactoryGirl.define do
factory :product do
name 'My awesome product'
price 100
description 'Just a simple awesome product'
# add there attributes you need
end
end

FactoryGirl + Mongoid + RSpec not properly constructing objects.

I am at trying to set up testing in my app, and I have run into a problem with RSpec, FactoryGirl, and Mongoid. I have the following factory:
FactoryGirl.define do
factory :user do |u|
u.name { Faker::Name.name }
u.email { Faker::Internet.email }
u.crypted_password { Faker::Lorem.characters(10) }
u.password_salt { Faker::Lorem.characters(10) }
u.role :user
end
end
I try to use this factory in my tests:
require 'spec_helper'
describe User do
it "has a valid factory" do
create(:user).should be_valid
end
end
But I get this error:
1) User has a valid factory
Failure/Error: FactoryGirl.create(:user).should be_valid
NoMethodError:
undefined method `user' for #<User:0x007ff24a119b28>
# ./spec/models/user_spec.rb:5:in `block (2 levels) in <top (required)>'
I don't know what is causing this error. Also, is there a way to see a full stacktrace using rspec?
This line has problem
u.role :user
I guess you want to define a default role as "user"? Then don't use symbol or method, use string instead
u.role 'user'

testing controller with spec and factory girl, can't sign_in

I'm newbie on rails and testing rails applications. I try to test an existing rails application with rspec. I've just finished model tests and i have to complete controller tests too.But i have a problem with sign_in method on rspec. I've tried all solution methods on the internet but still i can't sign in like a user with rspec.
here is the my controller code, it's too simple;
class AboutController < ApplicationController
def index
end
def how_it_works
end
def what_is
end
def creative_tips
end
def brand_tips
end
def we_are
end
def faq
end
end
and here is the my spec code;
require 'spec_helper'
describe AboutController do
before(:all) do
#customer=Factory.create(:customer)
sign_in #customer
end
context 'index page :' do
it 'should be loaded successfully' do
response.should be_success
end
end
end
Here is the my factory code;
Factory.define :unconfirmed_user, :class => User do |u|
u.sequence(:user_name) {|n| "user_#{n}"}
u.sequence(:email){|n| "user__#{n}#example.com"}
u.sequence(:confirmation_token){|n| "confirm_#{n}"}
u.sequence(:reset_password_token){|n| "password_#{n}"}
u.password '123456'
u.password_confirmation '123456'
u.user_type :nil
end
Factory.define :user, :parent => :unconfirmed_user do |u|
u.confirmed_at '1-1-2010'
u.confirmation_sent_at '1-1-2010'
end
Factory.define :customer, :parent => :user do |u|
u.user_type :customer
end
Finally here is the my spec_helper code
ENV["RAILS_ENV"] ||= 'test'
require File.dirname(__FILE__) + "/../config/environment" unless defined?(Rails)
require 'rspec/rails'
require "paperclip/matchers"
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
config.include Paperclip::Shoulda::Matchers
end
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
RSpec.configure do |config|
config.mock_with :rspec
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
end
gem file;
gem 'rails', '3.0.3'
gem 'mysql2', '< 0.3'
.
.
.
gem "devise" , "1.1.5"
.
.
.
group :test do
gem 'shoulda'
gem "rspec-rails", "~> 2.11.0"
gem "factory_girl_rails"
end
and here is the error;
Failures:
1) AboutController index page : should be loaded successfully
Failure/Error: sign_in #customer
NoMethodError:
undefined method `env' for nil:NilClass
# ./spec/controllers/about_controller_spec.rb:7:in `block (2 levels) in <top (required)>'
solution must be too easy but I'm newbie on rails and i can't find it :(
You have to make the sign-in step inside the it block in order for rspec to be able to access the response, e.g.:
it 'should be loaded successfully' do
sign_in #customer
response.should be_success
end
You have no subject.
require 'spec_helper'
describe AboutController do
before(:all) do
#customer=Factory.create(:customer)
sign_in #customer
end
context 'index page :' do
subject { Page }
it 'should be loaded successfully' do
response.should be_success
end
end
end
You might need to visit customers_path.

Resources