Why my example is passing test without model validation? - ruby-on-rails

I've got the following model and test file. To my understanding, the last example should fail until I validate the body attribute in the model but it's passing the test. I'm not sure what it is that I'm missing. Any assistance is highly appreciated in advance, thanks.
article.rb
class Article < ApplicationRecord
validates :title, presence: true, length: { in: 6..25 }
end
article_spec.rb
require 'rails_helper'
RSpec.describe Article, type: :model do
subject { Article.new(title: 'Lorem ipsum dolor sit, amet ', body: 'consectetur adipisicing elit. Unde, labore?') }
before { subject.save }
it 'is not valid without a title' do
subject.title = nil
expect(subject).to_not be_valid
end
it 'is not valid if the title is too short' do
subject.title = 'a'
expect(subject).to_not be_valid
end
it 'is not valid if the title is too long' do
subject.title = 'a' * 26
expect(subject).to_not be_valid
end
it 'is not valid without a body' do
subject.body = nil
expect(subject).to_not be_valid
end
end

You are missing the validation for the body attribute.
class Article < ApplicationRecord
validates :title, presence: true, length: { in: 6..25 }
validates :body, presence: true
end

Related

Rails - FactoryGirl - test models [validation]

I would like to test my models but all informations that I could find seems to be outdated. My goal is to test each individual validation.
My model:
class Author < ActiveRecord::Base
has_and_belongs_to_many :books
before_save :capitalize_names
validates :name, :surname, presence: true, length: { minimum: 3 },
format: { with: /[a-zA-Z]/ }
private
def capitalize_names
self.name.capitalize!
self.surname.capitalize!
end
end
and my factorygirl define:
FactoryGirl.define do
factory :author do |f|
f.name { Faker::Name.first_name }
f.surname { Faker::Name.last_name }
end
end
So now, I want to test whether name is not shorter than 3 characters.
My context:
context 'when first name is too short' do
it { expect( FactoryGirl.build(:author, name: 'Le')).to
be_falsey }
end
I know it's invalid because of [FactoryGirl.build(:author, name: 'Le')] returns hash instead of boolean value. So now, how should I test it? What matcher should I use?
[SOLVED]
Use be_valid instead of be_falsey. Now it should look like :
context 'when first name is too short' do
it { expect( FactoryGirl.build(:author, name: 'Le')).not_to
be_valid }
end

Using FactoryGirl for resource that belongs to 2 other resources and validates their id's in Rails 4 app

My associations aren't so complex but I've hit a wall making them work with FactoryGirl:
Text: blast_id:integer recipient_id:integer
class Text < ActiveRecord::Base
belongs_to :blast
belongs_to :recipient, class_name: "User"
validates :blast_id, presence: true
validates :recipient_id, presence: true
end
Blast: content:string author_id:integer
class Blast < ActiveRecord::Base
belongs_to :author, class_name: "User"
has_many :texts
validates :author_id, presence: true
end
User: name:string, etc. etc.
class User < ActiveRecord::Base
has_many :blasts, foreign_key: "author_id"
validates :name, presence: true
end
In FactoryGirl I've got:
FactoryGirl.define do
factory :user, aliases: [:author, :recipient] do |u|
sequence(:name) { Faker::Name.first_name }
end
factory :blast do
author
content "Lorem ipsum"
ignore do
texts_count 1
end
after :build do |blast, evaluator|
blast.texts << FactoryGirl.build_list(:text, evaluator.texts_count, blast: nil, recipient: FactoryGirl.create(:user) )
end
end
factory :text do
blast
association :recipient, factory: :user
end
end
Finally, some specs which all fail because Texts is not valid
require 'spec_helper'
describe Text do
User.destroy_all
Blast.destroy_all
Text.destroy_all
let!(:user) { FactoryGirl.create(:user) }
let!(:blast) { FactoryGirl.create(:blast, author: user) }
let(:text) { blast.texts.first }
subject { text }
it { should be_valid }
describe "attributes" do
it { should respond_to(:blast) }
it { should respond_to(:recipient) }
its(:blast) { should == blast }
its(:recipient) { should == recipient }
end
describe "when blast_id is not present" do
before { text.blast_id = nil }
it { should_not be_valid }
end
describe "when recipient_id is not present" do
before { text.recipient_id = nil }
it { should_not be_valid }
end
end
All the specs fail on FactoryGirl blast creation with:
1) Text
Failure/Error: let!(:blast) { FactoryGirl.create(:blast, author: user) }
ActiveRecord::RecordInvalid:
Validation failed: Texts is invalid
# ./spec/models/text_spec.rb:8:in `block (2 levels) in <top (required)>'
I've tried various iterations of the association code in the FactoryGirl docs and other question answers like this one but my situation is different enough that I can't get it to work.
If you've made it this far, thank you! Super grateful for any leads.
Your factory for "blast" should look like
factory :blast do
author
content "Lorem ipsum"
ignore do
texts_count 1
end
after :build do |blast, evaluator|
blast.texts << FactoryGirl.build_list(:text, evaluator.texts_count, blast: blast, recipient: FactoryGirl.create(:user) )
end
end
In other words, you immediately create the correct "parent" by connecting the newly created blast to the newly created tekst
To further dry your code, have a look at https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#configure-your-test-suite, describing how to get rid of using "FactoryGirl." over and over again by setting
config.include FactoryGirl::Syntax::Methods
once in your settings

All rspec tests passing when they should not (Rails 3.2, Rspec)

I'm building a daily deal rails app and I have followed M. Hartl tutorial to set some rspec tests.
For users they work perfectly.
But now I have used it for the model Eals and all are passing, when they shouldn't. For example, in my models, I put that titles can't be longer than 200 characters (note:on my view, when I try to set titles longer than this, it works and alerts me it's not possible)
But when I do tests no matter if I try for the title character length's test with long = "a" * 50, a * 201 or even a * 10000 in the title test, it always pass! There is a big problem I don't manage to find.
And actually all the other tests have the same problem: they always pass!
Here is my models/deal.rb
class Deal < ActiveRecord::Base
belongs_to :admin_user
attr_accessible :url_path,
:country,
:title,
:description,
:twitter_msg,
:admin_user_id
validates :url_path,
presence: true,
uniqueness: { :case_sensitive => false }
validates :country,
:inclusion => { :in => ['France', 'Germany', 'United States'],
:message => "%{value} is not a valid country. " }
validates :title,
presence: true,
length: { maximum: 200,
:message => "Your title has %{value} characters but must be shorter than 200 characters" }
validates :description,
presence: true,
length: { maximum: 500,
:message => "Your title has %{value} characters but must be shorter than 500 characters" }
validates :twitter_msg,
presence: true,
uniqueness: { :case_sensitive => false }
validates :admin_user_id, presence: true
And my deal_spec.rb:
require 'spec_helper'
describe Deal do
let(:admin_user) { FactoryGirl.create(:admin_user) }
before (:each) do
#attr = { url_path: "lorem ipsum",
country:"France",
title: "lorem ipsum",
description:"lorem ipsum",
twitter_msg:"lorem ipsum",
}
end
it { should respond_to(:url_path) }
it { should respond_to(:country) }
it { should respond_to(:title) }
it { should respond_to(:description) }
it { should respond_to(:twitter_msg) }
describe "title test" do
it "should reject deals with title that is too long" do
long = "a" * 50
hash = #attr.merge(:title => long)
Deal.new(hash).should_not be_valid
end
[other tests]
end #end of title test
If anybody can help me understand that, that would be great, I have been spending hours without any clue.
After following sb advice, I changed my test with
Deal.new(hash).should have(1).error_on(:title)
describe "test" do
it "should reject games with title that is too long" do
long = "a" * 250
hash = #attr.merge(:title => long)
Game.new(hash).should have(1).error_on(:title)
end
end
But now it's passing all the time, i.e it's telling me I have one error on title no matter if I put long= "a" * 5, long="a" * 300...
This is not the correct way to test validation using RSpec because it doesn't tell you why the object is invalid. It may be invalid because you're missing a totally different attribute that the one you're testing for. You should be using the have(x).errors_on(y) assertion:
Deal.new(hash).should have(1).error_on(:title)
I recommend using shoulda_matchers for testing such things
Could you please try the following code? It should give you a hint what attribute is invalid (and why):
it "..." do
d = Deal.new(#attr)
d.valid?
puts d.errors.full_messages
end
admin_user_id is not in your #attr hash. However it's mandatory on your Deal model - so your test always passes because the new deal is not valid. Nothing to do with the length of the title.

Testing carrierwave keeps returning "Image can't be blank"-error

I've been implementing carrierwave, which works great in the browser. However, my tests keep returning this:
Error
1) Item
Failure/Error: it { should be_valid }
expected valid? to return true, got false
# ./spec/models/item_spec.rb:36:in `block (2 levels) in <top (required)>'
factories.rb
include ActionDispatch::TestProcess
FactoryGirl.define do
sequence(:email) { |n| "User#{n}#example.com"}
factory :user do
name "John doe"
email
password "foobar"
password_confirmation "foobar"
end
factory :list do
name "Lorem ipsum"
user
end
factory :item do
image { fixture_file_upload(Rails.root.join('spec', 'support', 'test_images', 'google.png'), 'image/png') }
title "Shirt"
link "www.example.com"
list
end
end
item_spec.rb
require 'spec_helper'
describe Item do
let(:user) { FactoryGirl.create(:user) }
let(:list) { FactoryGirl.create(:list) }
before do
#item = list.items.build(title: "Lorem ipsum")
#item.valid?
puts #item.errors.full_messages.join("\n")
end
subject { #item }
it { should respond_to(:title) }
it { should respond_to(:list_id) }
it { should respond_to(:list) }
it { should respond_to(:image) }
it { should respond_to(:remote_image_url) }
its(:list) { should == list }
it { should be_valid }
describe "when list_id not present" do
before { #item.list_id = nil }
it { should_not be_valid }
end
describe "when image not present" do
before { #item.image = "" }
it { should_not be_valid }
end
describe "with blank title" do
before { #item.title = " " }
it { should_not be_valid }
end
describe "with title that is too long" do
before { #item.title = "a" * 141 }
it { should_not be_valid }
end
end
item.rb
class Item < ActiveRecord::Base
attr_accessible :link, :list_id, :title, :image, :remote_image_url
belongs_to :list
mount_uploader :image, ImageUploader
validates :title, presence: true, length: { maximum: 140 }
validates :list_id, presence: true
validates_presence_of :image
end
I have a image in the spec/support/test_images folder called google.png.
I'm very new to rails, and any help is thus much appreciated!
it { should be_valid }
is failing because (as you might expect) the subject is not valid. You need to find out why it is invalid. Try something like this:
it "should be valid" do
subject.valid?
subject.errors.should be_empty
end
Now the example will fail, but the error message will be more descriptive.
Another way to approach this is to add pry to your project. Then add binding.pry where you'd like to open a console:
it "should be valid" do
subject.valid?
binding.pry
subject.errors.should be_empty
end
Now you can inspect your test objects to figure out how the validation failed.
I feel quite stupid. Forgot to attach an image, which obviously caused the validation to fail.
Had to change:
before do
#item = list.items.build(title: "Lorem ipsum")
#item.valid?
puts #item.errors.full_messages.join("\n")
end
To:
before do
#item = list.items.build(title: "Lorem ipsum")
#item.image = fixture_file_upload('/test_images/google.png', 'image/png')
end

Rspec test for validity of new object not passing

I worked through all of Michael Hartl's Ruby on Rails Tutorial with all the tests passing. Now that I'm going back and making changes to the site to suit my own needs, it's not as cut and dry as "the tests in this section aren't passing." I've created a new "Charity" object that is strongly based on Hartl's "Micropost" object. The only difference is that instead of having "content" the object has a :name, :description and :summary.
This is the code for the test that is failing, (specifically "it { should be_valid }") which is located in /charity_spec.rb:
require 'spec_helper'
describe Charity do
let(:user) { FactoryGirl.create(:user) }
before { #charity = user.charities.build(summary: "Lorem ipsum") }
subject { #charity }
it { should respond_to(:name) }
it { should respond_to(:user_id) }
it { should respond_to(:summary) }
it { should respond_to(:description) }
it { should respond_to(:user) }
its(:user) { should == user }
it { should be_valid }
...
The test actually passes at first, but once I add the validations to the charity.rb file, they return;
Failures:
1) Charity
Failure/Error: it { should be_valid }
expected valid? to return, true, got false
...
Here's the charity.rb:
class Charity < ActiveRecord::Base
attr_accessible :name, :description, :summary
belongs_to :user
validates :name, presence: true, length: { maximum: 40 }
validates :summary, presence: true
validates :description, presence: true
validates :user_id, presence: true
default_scope order: 'charities.created_at DESC'
end
I'm sure it's something stupid, but my understanding of everything is so weak I can't figure out what I'm doing wrong, my feeling is that it's something wrong with my factory, but I really don't know.
Here's my charity factory located in the factories.rb:
factory :charity do
name "Lorem ipsum"
summary "Lorem ipsum"
description "Lorem ipsum"
user
end
When I remove the :name, :summary, and :description validations from charity.rb, the test passes. For good measure, here's the beginning of my user.rb:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :charities
has_many :microposts, dependent: :destroy
Use your factory to have a proper charity:
before { #charity = user.charities.build(FactoryGirl.attributes_for(:charity)) }
It failed because you validate presence of attributes which were not set like name
If you need more background on FactoryGirl, their documentation is really good.

Resources