How to write spec for ActiveRecord - ruby-on-rails

My spec/models code as require 'spec_helper'
describe Student do
it "should be work" do
student = Student.find 1
puts student.version
end
end
When running the code it shows the following error..,
Failures:
1) Student should be work
Failure/Error: student = Student.find 2
ActiveRecord::StatementInvalid:
Could not find table 'students'
# ./spec/models/student_spec.rb:6:in `block (2 levels) in <top (require
Finished in 0.00109 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/models/student_spec.rb:4 # Student should be work
I'm having students table.Also, I'm using paper_trail gem.
After running rake db:test:prepare then it shows an error as.,
Failures:
1) Student should be work
Failure/Error: s = Student.find 1
ActiveRecord::RecordNotFound:
Couldn't find Student with id=1
# ./models/student_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.02182 seconds
1 example, 1 failure
Failed examples:
rspec ./models/student_spec.rb:4 # Student should be work

It seems there is no table students in test environment, try to run
$ bundle exec rake db:test:prepare

Do you have propagated some data in your test database (using fixtures or something like FactoryGirl gem)?
Otherwise you wouldn't find any "students" in your DB.
Test-DB and Development DB have nothing in common. In fact the Test-DB will be cleared for each test.

The problem is there is no studend with id=1 in the students table of the test DB (the test DB is cleared before start new tests).
What do you want to test?
Maybe you want to use the before to insert a student at the start of the spec:
describe Student do
before do
#student = Student.new(:version => 15)
#student.save
end
it "should be work" do
student = Student.first
# Test something ...
end
end
The before block is run before every test, in this case you can get the first student in the (test) DB because you inserted it in the before block (but I don't know what you're trying to test and if save a student is really needed).

Related

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).

undefined method `first_name=' Rspec + Factories

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"

FactoryGirls randomly fails with 'Factory not registered', why?

I've some tests that randomly fail, approx. 20% of times. It means that WITHOUT changing the code, each time that I run the tests 1 time out of 5 will fail with "Factory not registered" error. It's very weird.. :(
This is the consone output:
Failures:
1) Unit#new_from_string returns factor for metric conversions
Failure/Error: FactoryGirl.create :taza
ArgumentError:
Factory not registered: taza
# ./spec/models/unit_spec.rb:29:in `block (2 levels) in <top (required)>'
Finished in 0.29619 seconds
4 examples, 1 failure
Failed examples:
rspec ./spec/models/unit_spec.rb:22 # Unit#new_from_string returns factor for metric conversions
Randomized with seed 61727
And this is the code:
file: "unit_spec.rb"
require 'spec_helper'
describe Unit, "#new_from_string" do
it "parses the string and returns a Unit object" do
[some tests...]
FactoryGirl.find_definitions
u = FactoryGirl.create :taza
FactoryGirl.create :tbsp
[tests...]
end
it "returns factor for metric conversions" do
[tests not involving factory girl...]
# the following is line 29, that fails
FactoryGirl.create :taza
[tests...]
end
end
file "spec/factories/units.rb":
FactoryGirl.define do
factory :taza , :class => CustomUnit do
singular 'taza'
plural 'tazas'
physical_type Unit::VOLUME
equivalence_factor 200
equivalence_unit 'ml'
end
[other factories...]
end
I think the problem is on this line
FactoryGirl.find_definitions
Actually there is no need for this line when your factories are in correct directories(I see it is), and you put gem factory_girl_rails in Gemfile.
I think, 20% of time, the second test get run at first. At this time, there is no definition of Factory and the test failed. The other test has such definition and get passed. In other time, the first test run first so definition exists.
My suggestion:
Make sure you have factory_girl_rails, not factory_girl in Gemfile.
Remove that line of definition.
[optional but recommended] Put all definition in a single file spec/factories and remove all other factory files, if you don't have too much factories. This would be easier to manage.

Rails: When unit testing, are "failures" or "errors" are desired in the beginning?

Hi I'm trying to learn testing and TDD, so I started a new project and made a User model. I made a User model with: name, gender, age.
class User < ActiveRecord::Base
attr_accessible :age, :gender, :name
end
I read that TDD is about making tests (that fail), fixing them, and then running the tests again to see them pass. So does that mean I want a failure first or error or do either work?
I'm asking because I just wrote a second test:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "user is created" do
user = User.create(:name => "Edmund", :age => 3, :gender => "m")
assert_equal user, User.find_by_name("Edmund")
assert_equal 3, User.count
end
test "user has sent messages" do
user = User.create(:name => "Edmund", :age => 3, :gender => "m")
2.times do
user.sent_messages.create(:sender_id => user.id)
end
assert_equal 2, user.sent_messages.count
end
end
for sent messages. I ran rake test:units, expecting it to be a failure since I don't have any Message model nor any association with has_many :messages in my User model, however I got an error:
Edmunds-MacBook-Pro:langoexchange edmundmai$ rake test:units
NOTICE: CREATE TABLE will create implicit sequence "users_id_seq" for serial column "users.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
Run options:
# Running tests:
E.
Finished tests in 0.087926s, 22.7464 tests/s, 22.7464 assertions/s.
1) Error:
test_user_has_sent_messages(UserTest):
NoMethodError: undefined method `sent_messages' for #<User:0x007fa73bbd68e0>
/Users/edmundmai/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/activemodel-3.2.8/lib/active_model/attribute_methods.rb:407:in `method_missing'
/Users/edmundmai/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/activerecord-3.2.8/lib/active_record/attribute_methods.rb:149:in `method_missing'
/Users/edmundmai/Desktop/Class/Ruby/langoexchange/test/unit/user_test.rb:13:in `block (2 levels) in <class:UserTest>'
/Users/edmundmai/Desktop/Class/Ruby/langoexchange/test/unit/user_test.rb:12:in `times'
/Users/edmundmai/Desktop/Class/Ruby/langoexchange/test/unit/user_test.rb:12:in `block in <class:UserTest>'
2 tests, 2 assertions, 0 failures, 1 errors, 0 skips
rake aborted!
Command failed with status (1): [ruby -I"lib:test" -I"/Users/edmundmai/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rake-10.0.2/lib" "/Users/edmundmai/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rake-10.0.2/lib/rake/rake_test_loader.rb" "test/unit/**/*_test.rb" ]
Tasks: TOP => test:units
(See full trace by running task with --trace)
Is this (error) the expected outcome of TDD or did I do something wrong or interpret the process of TDD incorrectly?
Yes, this is the expected first step in TDD. Once you've written your first test(s), your next task is to get your code up to the point where you get actual failures as opposed to errors. A failure is different from an error because it means that your test was expecting something, and that expectation was not met. In the case of an error, the expectation never even gets a chance to be tested because something breaks in the code under test. (In your case, the spec never gets a chance to check whether user.sent_messages.count is equal to 2 because sent_messages is not even defined.)
The TDD cycle typically focuses on getting from red (failure) to green (success + refactor) because this is the important part of the process, but implicit in this cycle is the process from errors (undefined variables/methods, etc.) to actual failures (expectations not met, etc.) Usually that first step from error to failure is a fairly trivial one (in this case, define a method called sent_messages with nothing in it to start, and run the test again), but it may not be depending on context.
Yes, your tests are initially supposed to fail (else, there's no work to be done), then you do the minimum to make it pass. Every so often (I do every 20 tests when doing TDD), you refactor them.

Rspec not finding committed changes to an object

i'm new to rspec and ruby...
i have the following code in one of course_rspec.rb
...
it "check for active courses after enabling a course" do
course = Course.create(:title => "Testing", :description => "Testing")
course.enabled = true
course.save
active_courses = Course.where(:enabled => true)
active_courses.length.should eql 1
end
...
i get the following error
1) Course check for active courses after enabling a course
Failure/Error: active_courses.length.should eql 1
expected: 1
got: 0
(compared using eql?)
# ./course_spec.rb:86:in `block (2 levels) in <top (required)>'
why is the Course.where method return no objects? when i do this in rails console it works fine.
thanks for your help.
Are you running rails console in the test mode or in the development mode? Keep in mind that rails for testing and developing an application uses different databases.
Make sure that before the test all records are prepared and stored in the database. For this purpose you could use fixtures or factories (factory_girl for example).
ps.
Instead active_courses.length.should eql 1 you can use active_courses.should have(1).item which is more readable.

Resources