Tests fail with record creation in Rails 5 - ruby

I am building an app in school and I am running into this error. As of right now the app walk through was started in rails 4.2.6, and I am running 5.0.0.1.
The error is:
Failures:
1) Post Creation can be created
Failure/Error: expect(#post).to be_valid
expected #<Post id: nil, date: "2016-12-20", rationale: "Anything", created_at: nil, updated_at: nil, user_id: nil> to be valid, but got errors: User must exist
# ./spec/models/post_spec.rb:10:in `block (3 levels) in <top (required)>'
Finished in 0.65569 seconds (files took 2.19 seconds to load)
10 examples, 1 failure
Failed examples:
rspec ./spec/models/post_spec.rb:9 # Post Creation can be created
My code is as follows. I have compared to the repo on the walk-through and it matches perfectly. What am i missing?
require 'rails_helper'
RSpec.describe Post, type: :model do
describe "Creation" do
before do
#post = Post.create(date: Date.today, rationale: "Anything")
end
it "can be created" do
expect(#post).to be_valid
end
it "cannot be created without a date and rationale" do
#post.date = nil
#post.rationale = nil
expect(#post).to_not be_valid
end
end
end

Rails 5 differs from Rails 4 in that when you have a belongs_to relation, Rails 5 will automatically validate the presence of the associated object, even without you adding any validations.
Probably your Post model belongs to a User. Because of this, you need to create a user in your test setup, or the validation will fail:
describe "Creation" do
before do
#user = User.create( ... )
#post = Post.create(date: Date.today, rationale: "Anything", user: #user)
end
it "can be created" do
expect(#post).to be_valid
end
it "cannot be created without a date and rationale" do
#post.date = nil
#post.rationale = nil
expect(#post).to_not be_valid
end
end

Related

An error occurred while loading ./spec/controllers/users_controller_spec.rb

I am creating factories to replace my fixtures and to generate Test Data. I've installed FactoryBot but I am getting an error when running "rspec". This is the outcome log I get:
An error occurred while loading ./spec/controllers/users_controller_spec.rb.
Failure/Error: #user = FactoryBot.create(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:5:in `block in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:3:in `<top (required)>'
Finished in 0.00041 seconds (files took 38.38 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples
This is my spec/factories/user_factory.rb
FactoryBot.define do
factory :user do
email "peter#example.com"
password "0123456"
first_name "Peter"
last_name "Example"
admin false
end
end
This is my spec/controllers/users_controller_spec.rb
require 'rails_helper'
describe UsersController, type: :controller do
#user = FactoryBot.create(:user)
# let (:user) { User.create!(email:"achochaocierva#gmail.com", password: "Ratadecierva2")}
describe 'GET #show' do
context 'when a user is logged in' do
before do
sign_in user
end
it 'loads correct user details' do
get :show, params: { id: user.id }
expect(response).to be_ok
expect(assigns(:user)).to eq user
end
end
context 'when a user is not logged in' do
it 'redirects to login' do
get :show, params: { id: user.id }
expect(response).to redirect_to(new_user_session_path)
end
end
end
end
What would be the errors meaning? What am I doing wrong?
What would be the errors meaning? What am I doing wrong?
Your factory tries to create a user with the same email as one of the existing users (no wonder, seeing that the email is hardcoded in the factory). Your DB's uniqueness constraint complains.
You should use sequences for user emails
# email "peter#example.com"
sequence(:email) { |n| "factory_#{n}#example.com" }
First user from this factory will have email "factory_1#example.com", second - "factory_2#example.com", and so on.

Ruby basic RSpec test does not pass

I'm not able to understand why the following Rspec test does not pass -
require "rspec"
require_relative "file-to-be-tested"
describe Customer do
it "is valid with firstname" do
customer = Customer.new("handy")
expect(customer).to be_valid
end
end
for the corresponding Class definition -
class Customer
attr_reader :firstname
def initialize(firstname)
#firstname = firstname
end
end
these two code snippets are in separate files in the same folder, so when i run ~rspec <first-filename> in the terminal, I get the following error -
F
Failures:
1) Customer is valid with firstname
Failure/Error: expect(customer).to be_valid
expected #<Customer:0x007f90e50f3110> to respond to `valid?`
# ./poodr/poodr_rspec.rb:8:in `block (2 levels) in <top (required)>'
Finished in 0.00551 seconds (files took 0.52876 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./poodr/poodr_rspec.rb:6 # Customer is valid with firstname
be_valid is an rspec-rails method, but it looks like you're using just straight rspec. you could do something like:
require "rspec"
require_relative "file-to-be-tested"
describe Customer do
it "is valid with firstname" do
expect { Customer.new('handy') }.to_not raise_error
end
end
What are you expecting the to be_valid test to do? The issue is that the Customer class has no method called valid? which your test is trying to test.
A hack to move your test along if your doing test driven development:
class Customer
def valid?
true
end
end
You now have a method called valid and your test will pass. Obviously it shouldn't always be true so your next step would be to expand the definition of valid?. What check needs to be done to know if a customer is valid or not?

Rails 4, rspec 3: model validation test

I have an organization object that has attributes name, doing_business_as. I need to validate that the name is not the same as doing_business_as.
# app/models/organization.rb
class Organization < ActiveRecord::Base
validate :name_different_from_doing_business_as
def name_different_from_doing_business_as
if name == doing_business_as
errors.add(:doing_business_as, "cannot be same as organization name")
end
end
end
I have a matching rspec file that verifies this:
# spec/models/organization_spec.rb
require "rails_helper"
describe Organization do
it "does not allow NAME and DOING_BUSINESS_AS to be the same" do
organization = build(:organization, name: "same-name", doing_business_as: "same-name")
expect(organization.errors[:doing_business_as].size).to eq(1)
end
end
When I run the spec, however, it fails and this is what I get:
$ rspec spec/models/organization_spec.rb
Organization
does not allow NAME and DOING_BUSINESS_AS to be the same (FAILED - 1)
Failures:
1) Organization validations does not allow NAME and DOING_BUSINESS_AS to be the same
Failure/Error: expect(organization.errors[:doing_business_as].size).to eq(1)
expected: 1
got: 0
(compared using ==)
# ./spec/models/organization_spec.rb:113:in `block (3 levels) in <top (required)>'
Finished in 0.79734 seconds (files took 3.09 seconds to load)
10 examples, 1 failure
Failed examples:
rspec ./spec/models/organization_spec.rb:110 # Organization validations does not allow NAME and DOING_BUSINESS_AS to be the same
I was expecting the spec to pass and ensure that the 2 attributes cannot be the same. In the Rails console I can mimic the expected behavior, but I can't seem to get the spec to "fail" successfully.
I also checked via the Rails Console that it works as expected:
$ rails c
> o = Organization.new(name: "same", doing_business_as: "same")
> o.valid?
=> false
> o.errors[:doing_business_as]
=> ["cannot be the same as organization name"]
So I know the functionality is there, but I can't get a workable test...
You need to use build method instead of create method.
# spec/models/organization_spec.rb
require "rails_helper"
describe Organization do
it "does not allow NAME and DOING_BUSINESS_AS to be the same" do
organization = build(:organization, name: "same-name", doing_business_as: "same-name")
organization.valid?
expect(organization.errors[:doing_business_as].size).to eq(1)
end
end
or
# spec/models/organization_spec.rb
require "rails_helper"
describe Organization do
it "does not allow NAME and DOING_BUSINESS_AS to be the same" do
organization = build(:organization, name: "same-name", doing_business_as: "same-name")
expect(organization).to be_invalid
end
end

Testing with Rspec codeschool level 3 challenge 5

I have been battling this test way too long and I am not sure where I am stuck. Here is the model I am trying to test:
class Zombie < ActiveRecord::Base
attr_accessible :iq
validates :name, presence: true
def genius?
iq >= 3
end
def self.genius
where("iq >= ?", 3)
end
end
Here is what I am working with to start:
describe Zombie do
context "with high iq" do
let(:zombie) { Zombie.new(iq: 3, name: 'Anna') }
subject { zombie }
it "should be returned with genius" do
Zombie.genius.should include(zombie)
end
it "should have a genius count of 1" do
Zombie.genius.count.should == 1
end
end
end
This is the part of the refactor that is working:
it { should be_genius }
#it "should have a genius count of 1" do
# Zombie.genius.count.should == 1
#end
Here is where I am currently stuck at with the refactor:
describe Zombie do
context "with high iq" do
let!(:zombie) { Zombie.new(iq: 3, name: 'Anna') }
subject { zombie }
it {should include("zombie")}
it { should be_genius }
end
end
According to the examples this should work, but no matter what I try it keeps bombing on the include. I know I am missing something lame here. Thoughts or tips anyone?
Current Error Message:
Failures:
1) Zombie with high iq
Failure/Error: it {should include("zombie")}
NoMethodError:
undefined method `include?' for #<Zombie:0x00000006792380>
# zombie_spec.rb:7:in `block (3 levels) '
Finished in 0.12228 seconds
2 examples, 1 failure
Failed examples:
rspec zombie_spec.rb:7 # Zombie with high iq
You need to add the ! to the let and change new to create in order to save the record.
describe Zombie do
context "with high iq" do
let!(:zombie) { Zombie.create(iq: 3, name: 'Anna') }
subject { zombie }
it "should be returned with genius" do
Zombie.genius.should include(zombie)
end
it "should have a genius count of 1" do
Zombie.genius.count.should == 1
end
end
end
I'm not sure what examples you are referring to that suggest your refactor should work, but the implicit subject zombie used in your first refactored example is an ActiveRecord instance and the include matcher you're using is intended to be used with a string, array or hash as described in https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/include-matcher.
As for your second refactored example, I gather it's working because you've only indicated a problem with the include.

Test failure gives incomplete error message when using short syntax

There are 2 syntaxes (afaik) for writing tests with RSpec:
The classic/old way:
describe "when user_id is not present" do
before { #micropost.user_id = nil }
it "should not be valid" do
#micropost.should_not be_valid
end
end
That gives this error when failing:
rspec ./spec/models/micropost_spec.rb:19 # Micropost when user_id is
not present should not be valid
And the short syntax:
describe "when user_id is not present" do
before { #micropost.user_id = nil }
it { should_not be_valid }
end
That gives this error when failing:
rspec ./spec/models/micropost_spec.rb:18 # Micropost when user_id is
not present
The last one is missing the "should not be valid" part.
Is there any way to have the complete test failure message, maybe a flag I don't know about?
Note: A more complete error message is still there no matter what:
1) Micropost when user_id is not present
Failure/Error: it { should_not be_valid }
expected #<Micropost id: nil, content: "Lorem ipsum", user_id: nil, created_at: nil, updated_at: nil> not to be valid
# ./spec/models/micropost_spec.rb:18:in `block (3 levels) in <top (required)>'
But the recap at the end is incomplete.
The text you see in
rspec ./spec/models/micropost_spec.rb:19 # Micropost1 when user_id is not present2 should not be valid3
and
rspec ./spec/models/micropost_spec.rb:18 # Micropost1 when user_id is not present2 3
is not the error message, but the test name, which is a concatenation of the current test's description with all its parents' descriptions:
describe Micropost do # <= 1
describe "when user_id is not present" do # <= 2
before { #micropost.user_id = nil }
it "should not be valid" do # <= 3
#micropost.should_not be_valid
end
end
end
In the short (one-liner) syntax - the test itself does not have a description
describe Micropost do # <= 1
describe "when user_id is not present" do # <= 2
before { #micropost.user_id = nil }
it { should_not be_valid } # <= 3 - not described!
end
end
If you want to force a description on this test you could write it like this:
it('should not be valid') { should_not be_valid }
But this kind of beats the purpose of the one-liner, which should be self-explanatory, don't you think?

Resources