undefined method `first_name=' Rspec + Factories - ruby-on-rails

I've been building my application and I'm now ready to start testing. I have Factory girl defined in seeds.rb but as I'm running tests I've also defined the tests in the usual place /spec/factories.rb for Rspec.
However my first tests fails with the following error.
user_spec.rb
require 'spec_helper'
describe User do
it "should have valid factory" do
FactoryGirl.build(:user1).should be_valid
end
end
Error returned:
Failures:
1) User should have valid factory
Failure/Error: FactoryGirl.build(:user1).should be_valid
NoMethodError:
undefined method `first_name=' for #<User:0x000000061410f8>
# ./spec/models/user_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.05459 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:4 # User should have valid factory
Randomized with seed 29084
spec/factories.rb
FactoryGirl.define do
factory :admin1, class: User do
first_name "admin"
last_name "minstrator"
password "admin1234"
profile_name "profilename"
email "admin#admin.com"
password_confirmation "admin1234"
admin true
end
factory :user1, class: User do
first_name "user2"
last_name "man2"
password "user1234"
profile_name "profilename"
email "user2#user.com"
password_confirmation "user1234"
admin false
end
end
It works fine when using the data on development in my seed.rb but now I've started testing using Rspec it has all gone wrong.
What am I doing incorrectly here. I'm not a huge fan of testing at the moment but I need to improve my skill set here as I know it can be extremely useful for web applications.
You help is greatly appreciated, please let me know if you need anymore info.

If your code works in development, but not in test, my guess is that your test copy of the database is not in sync. Try running rake db:test:prepare or rake db:test:clone and run your specs again.
Note:
db:test:clone isn't required in Rails 4.2.0 'WARNING: db:test:clone is deprecated. The Rails test helper now maintains your test schema automatically, see the release notes for details.')

I believe the issue here was that one of my migrations was missing and because it didn't have users first_name in the model there was nothing defined.
A big tip to all newbies, never ever ever delete any of your migrations.
As Homer Simpson quite rightly said "D'oh"

Related

Routes Increment when I Run Rspec feature

So, for some reason my routes increment by 11 when I run my comment feature test.
Exhibit A: I hit save on my comment_spec.rb
RSpec.feature "Adding comments to movies" do
before do
#kyle = Admin.create(email: "kyle#example.com", password: "password")
#jill = Member.create(email: "jill#example.com", password: "password")
#movie = Movie.create!(title: "First movie", synopsis: "Synopsis of first movie", year_released: '2000', admin: #kyle)
end
scenario "permits a signed in member to write a comment" do
login_as(#jill, scope: :member)
visit "/"
click_link #movie.title
fill_in "New Review", with: "An awesome movie"
click_button "Add Review"
expect(page).to have_content("Review has been created")
expect(page).to have_content("An awesome movie")
# must implement a nested route in order for this to work.
expect(current_path).to eq(movie_path(#movie.comments.last.id))
end
end
Then the test passes
moviesmoviesmovies/spec/features/comments_spec.rb:3)
Finished in 0.99879 seconds (files took 2.4 seconds to load) 1
example, 0 failures
Now, I hit enter in the terminal and get this:
Adding comments to movies permits a signed in member to write a comment
Failure/Error: expect(current_path).to eq(movie_path(#movie.comments.last.id))
expected: "/movies/2"
got: "/movies/4"
(compared using ==)
# ./spec/features/comments_spec.rb:26:in `block (2 levels) in <top (required)>'
Then I save the comment_spec.rb again and get this:
Adding comments to movies permits a signed in member to write a comment
Failure/Error: expect(current_path).to eq(movie_path(#movie.comments.last.id))
expected: "/movies/3"
got: "/movies/15"
(compared using ==)
# ./spec/features/comments_spec.rb:26:in `block (2 levels) in <top (required)>'
After this happens, I run:
bundle exec rails db:test:prepare
Then the tests pass again, but the above repeats. What in the world is making this happen? haha, but really?
My GitHub if needed.
The issue you're having is that your database isn't being reset after each feature test, as you likely expect it is. Specifically, the problem is with Capybara and the config.use_transactional_fixtures = true line which is set in your spec config.
Capybara effectively tests your application as an external process using a virtual browser. This means that your capybara tests only have visibility into the client-side behavior of your app (i.e. the page variable). In other words, from Capybara's perspective your app is a "Black box". Therefore, capaybara doesn't see controller objects like your session, params, or request variables, nor can it see or control the specific database transactions which occur during testing.
Rather than relying on transactional fixtures, consider using database cleaner, which manually resets the database after each feature test. You can find the gem here: https://github.com/DatabaseCleaner/database_cleaner. Make sure you follow the directions on integrating with Capybara: https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example.

Factory Girl undefined method for nil:NilClass

I have a controller spec something like this
describe :bizzaro_controller do
let(:credit_card_account) { FactoryGirl.build :credit_card_account }
it "doesn't blow up with just the stub" do
CreditCardAccount.stub(:new).and_return(credit_card_account)
end
it "doesn't blow up" do
credit_card_account
CreditCardAccount.stub(:new).and_return(credit_card_account)
end
end
Which results in this:
bizzaro_controller
doesn't blow up with just the stub (FAILED - 1)
doesn't blow up
Failures:
1) bizzaro_controller doesn't blow up
Failure/Error: let(:credit_card_account) { FactoryGirl.build :credit_card_account }
NoMethodError:
undefined method `exp_month=' for nil:NilClass
# ./spec/controllers/user/bizzareo_controller_spec.rb:5:in `block (2 levels) in <top (required)>'
# ./spec/controllers/user/bizzareo_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Finished in 0.23631 seconds
2 examples, 1 failure
My credit card factory looks like this:
FactoryGirl.define do
factory :credit_card_account do
exp_month 10
exp_year 2075
number '3'
end
end
My CreditCardAccount is an empty ActiveRecord::Base model
=> CreditCardAccount(id: integer, exp_month: integer, exp_year: integer, number: string)
Versions
0 HAL:0 work/complex_finance % bundle show rails rspec-rails factory_girl
/home/brundage/.rvm/gems/ruby-2.0.0-p247#complex_finance/gems/rails-4.0.0
/home/brundage/.rvm/gems/ruby-2.0.0-p247#complex_finance/gems/rspec-rails-2.14.0
/home/brundage/.rvm/gems/ruby-2.0.0-p247#complex_finance/gems/factory_girl-4.2.0
This should be working. all points that your test database is not correct.
RAILS_ENV=test rake db:drop db:create will drop and recreate your test database. Then try to run your rspec using the rake command, in order to migrate the database: rake rspec
I was having the same problem, but I think the cause of my problem was different. My solution, however, may perhaps be useful: I used the Fabrication gem (http://www.fabricationgem.org/) instead of FG.
The reason why I was having this problem was because I was trying to have FG create/build an object that was not ActiveRecord, it was only an ActiveModel, and it had to be initialized with arguments.
I didn't see in the Fabricator documentation an example totally like what I needed, but I got it with this syntax:
Fabricator(:my_class) do
on_init do
init_with("Company Name", "Fake second arg")
end
end
My problem was that in model I made a private method called :send (forgot that it is already used in Ruby).

stuck on validation error of email already taken

I am following railscast #275 with testing the forgot me password. I am having troubles getting past the email has already been taken error. With the coding I have by following the tutorial I am suppose to receive this error, "error for no link with title or text "password". Instead this is what I am getting, "Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)"
I have done a search, unable to find a solution for it.
Here's password_resets_spec.rb:
require 'spec_helper'
describe "PasswordResets" do
it "emails user when requesting password reset"
user = FactoryGirl.create(:user)
visit login_path
click_link "password"
fill_in "Email", :with => user.email
click_button "Reset Password"
end
factories.rb:
FactoryGirl.define do
factory :user do
sequence :email do |n| "test#{n}#example.com"
end
password "secret"
end
end
Here's what I did when I finally notice it started to work. I installed database cleaner. Then I did the commands:
rake db:reset
rake db:migrate
rake db:test:prepare
Following that I noticed I had to add a "do" to the end of " it "emails user when requesting password reset".
Now I have no errors and I can continue in my testing adventure. Thanks to those who tried to assist.
The factory definition seems OK.
I would start by making sure that your test database is empty before running the spec. There may be an existing user record "test1#example.com" lingering. Also, have you tried to run only that example? Does it make any difference?
Looks like while running your test cases the factory that was created didn't rolled back/deleted the record.
add a before(:each) deletes previous records before the example executes
before(:each) do
User.delete_all
end

NameError: uninitialized constant Factory

I'm following this tutorial to get started with TDD on rails with factory girl, rspec and i ran into this issue i can't get my head around.
Here's my "factory".rb (events.rb)
require 'faker'
FactoryGirl.define do
factory :event do
name "HIGH"
genre "house, techno, idb"
venue_name "Westbourne Studios"
venue_address "4-6 Chamberlayne Road"
venue_postcode "NW103JD"
begin_time "10pm"
end_time "2am"
user_id 2
description "A Super massive party with loads of everything you would want around."
status true
venue_id nil
end
end
and here's the event_spec.rb:
require 'spec_helper'
require 'factory_girl_rails'
describe Event do
it "has a valid factory" do
Factory.create(:event).should be_valid
end
it "is invalid without a name"
it "is invalid without a genre"
it "is invalid without a venue_name"
it "is invalid without a venue_address"
it "is invalid without a venue_postcode"
...
end
I have setup the model, migrated etc.. and when i run "rspec spec/models/event_spec.rb" i get the following error:
Failures:
1) Event has a valid factory
Failure/Error: Factory.create(:event).should be_valid
NameError:
uninitialized constant Factory
# ./spec/models/event_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.1682 seconds
13 examples, 1 failure, 12 pending
Failed examples:
rspec ./spec/models/event_spec.rb:6 # Event has a valid factory
Randomized with seed 64582
Try to use it in this way:
FactoryGirl.create(:event).should be_valid
I think, I can remember, that it was only "Factory" in old versions of the gem. If you take a look in the recent "Getting started" guide of Factory Girl, there are only calls with "FactoryGirl".
If you create file spec/support/factory_girl.rb with content:
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
Then you can simply use:
create(:event)
build(:book)
Instead of:
FactogyGirl.create(:event)
FactogyGirl.build(:book)
I had the same error with factory bot, and to supplement Stefan's answer I came across this little cheat sheet.
https://devhints.io/factory_bot

RSpec failure: could not find table after migration...?

I have a naked rails 3 app with one model, generated using rails g model User.
I've added a factory (using factory_girl_rails):
Factory.define :user do |f|
f.email "test#test.com"
f.password "blah"
f.password_confirmation "blah"
f.display_name "neezer"
end
Then I've added one test:
require 'spec_helper'
describe User do
subject { Factory :user }
it "can be created from a factory" do
subject.should_not be_nil
subject.should be_kind_of User
end
end
Then I migrate my database using rake db:migrate.
Then I run the test using rspec spec, and the test fails with the following:
Failures:
1) User can be created from a factory
Failure/Error: subject { Factory :user }
ActiveRecord::StatementInvalid:
Could not find table 'users'
# ./spec/models/user_spec.rb:5:in `block (2 levels) in <top (required)>'
# ./spec/models/user_spec.rb:8:in `block (2 levels) in <top (required)>'
I'm confused, because I did just migrate my database, and my schema.db file reflects that there is a users table present, so what gives?
I know this is a beginner question, but banging my head against a wall isn't working...
factory_girl (1.3.3)
factory_girl_rails (1.0.1)
rails (3.0.5)
rspec-rails (2.5.0)
sqlite3 (1.3.3)
Try to execute
rake db:test:prepare
This should fix your tests db.
The point here is that rspec command doesn't execute migrations on your test database. and rake db:migrate only runs migrations in your current environment, probably development. Others environment like production and test ends without having those changes.
You can run
rake spec
That will prepare your testing db (drop and create using schema.rb) and run all tests.
As the other answer suggested, this:
rake db:test:prepare
Will also setup your testing db, but you have to run the rspec command after that, so, personally I prefer the first option.
try this out:
For rails version > 4.1+ this solution will work as the current scenario.
but in Rails 4.1+, rake db:test:prepare is deprecated.
try using
rake db:migrate RAILS_ENV=test (it will work for all version of rails)

Resources