I am writing some unit tests in Ruby on Rails. Even when I expect the test to have an outcome that passes the validation, the test fails.
Here is my model that I am testing:
class Post < ApplicationRecord
def permitted_params
params.require(:post).permit(:title, :body, :category_id, :admin_user_id)
end
belongs_to :category
belongs_to :admin_user
has_many :comment, :dependent => :destroy
validates :title, presence: false
validates_length_of :body, :minimum => 0
end
Here are my tests for this model:
class PostTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
test "If title is there" do
post = Post.create(:title => "", :body => "")
assert post.valid?
end
test "If body is long enough" do
post = Post.create(:title => "Some Title", :body => "hhhhhhhhhhhhhhhhhhhhhhhhh")
assert post.valid?
end
end
This is the error message:
F
Failure:
PostTest#test_If_title_is_there [test/models/post_test.rb:9]:
Expected false to be truthy.
I get two failures after running my test. I am using Ruby on Rails version 5.2.1 and Ruby version 2.5.1. Any help would be much appreciated. I am not quite sure why both tests are failing. Thank you in advance.
There is no point in having validates :title, presence: false
Most probably you want to validate the presence of title, so you should have presence: true.
In addition, I don't see any sense for validating length, against zero.
Also, I'd edit your code in the following way, since there is no point in having strong_parameters in the model.
class Post < ApplicationRecord
belongs_to :category
belongs_to :admin_user
has_many :comment, dependent: :destroy
validates :title, presence: false
validates :body, length: { minimum: 0 }
end
And finally, you can use https://github.com/thoughtbot/shoulda-matchers for more convenient validations testing.
To answer your question on why both tests are failing, the reason I believe is with validates :title, presence: false like others have pointed out and I don't think it's needed here.
1) I believe the first one fails because you are setting the title to an empty string. I could be wrong, but try setting it to nil and see if it still fails.
2) Similar to the first test, you are setting a title while your code expects it to not be present, causing the validation to also fail.
Hope this helped clearing some things up for you.
Related
I need to unit test a promotions model where every campaign has a URL. There is a polymorphic association between promotions and reference_link. the reference link fixture:
reference_link:
linkable:
fix_1 (PromoCode)
How do I convince rails that the promotions fixture does indeed have a URL belonging to it?
In promotions test helper:
test "should have a URL associated with the promo code" do
promo_code = promo_codes(:fix_1)
promo_code.reference_link.url = nil
assert_not promo_code.valid?
promo_code2 = promo_codes(:fix_2)
assert promo_code2.valid?
end
promocode.rb
class PromoCode < ActiveRecord::Base
belongs_to :reward
has_one :reference_link, as: :linkable, dependent: :destroy
validates :email, presence: true
validates :code, presence: true
end
reference_link.rb
class ReferenceLink < ActiveRecord::Base
belongs_to :linkable, polymorphic: true,touch: true
validates :link_name, presence: true
validates :link_url, presence: true
validates_format_of :link_url, :with => /\A#{URI::regexp(['http', 'https'])}\z/
validates_length_of :link_url,:link_name, :maximum => 255
end
It's simple, you almost got it right. First, ensure the fixtures are correctly set:
# promo_codes.yml
promo_1:
email: 'foobar#gmail.com'
name: 'Foobar'
# reference_links.yml
reference_1:
linkable: promo_1
link_name: 'lorem'
link_url: 'http://loremipsum.com'
The tests:
# promotion_test.rb
test "should have a URL associated with the promo code" do
promo_code = promo_codes(:promo_1)
assert_eq true, promo_code.reference_link.present?
end
Do not forget that file naming is an important part of convention that Rails use.
I have model Order:
class Order < ActiveRecord::Base
has_one :shipping_address
has_and_belongs_to_many :books
validates :first_name, :surename, :email, :street1, :country, :zipcode, presence: true
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
validates :zipcode, numericality: true
accepts_nested_attributes_for :shipping_address
end
and model Book:
class Book < ActiveRecord::Base
DEFAULT_PRICE = 55.15
NEXT_BOOK_PERCENT = 5
has_and_belongs_to_many :pages
has_and_belongs_to_many :orders
validates :name, presence: {message: "Name can't be blank."}
validates_length_of :name, minimum: 3, maximum: 12, message: "Sorry, we can't create this book right now. Please contact us for further information."
validate :same_letter_validation
validate :validates_for_non_alphabetic
before_save :compile
#......
end
Also I have table books_orders (book_id, order_id)
When I try do delete order from RailsAdmin panel I get next error:
NoMethodError in RailsAdmin::Main#delete
undefined method `orders_books' for #
It says that error in this line:
- #abstract_model.each_associated_children(object) do |association, child|
Have you defined that "orders_books" method anywhere in your code? If so, can you please add it to your question. If you haven't, then the root cause of your issue is just that, that you're calling the "orders_books" method but it is not yet defined
Given that you reference "#books_orders" in your question, I believe it likely that you just swapped "books_orders" and "orders_books" at some point in your code
Thanks. It's bug of a Rails 4.1.1. I have update it to 4.1.4 and all works OK.
Real newb question here: I've got courses
class Course < ActiveRecord::Base
attr_accessible :name, :number
has_many :posts
validates :name, presence: true
validates :number, presence: true
validates :number, :format => { :with => /\A\d\d[-]?\d\d\d\z/}
end
and I've got posts
class Post < ActiveRecord::Base
attr_accessible :comments, :course_id, :difficulty, :enjoyability, :hours, :professor, :ranking, :semester, :usefulness
belongs_to :course
end
Almost everything I have was auto-generated by Rails. There are a couple of things I try to do that I can't get to work:
When I "show" a course, I want to show each post associated with that course. However, everything I've tried has given me an error.
After even entering one post into the database (heroku forced me to use PostgreSQL) the index form no longer renders.
I'm almost positive I'm missing something with my associations between them. Does anybody have any ideas as to what I'm doing wrong?
You may get all posts through Course instance:
#course = Course.find(params[:id])
#posts = #course.posts
Model order.rb
class Order < ActiveRecord::Base
attr_accessible :address, :email, :name, :payment_type_id
belongs_to :payment_type
PAYMENT_TYPES = PaymentType.pluck(:id)
validates :name, :address, :email, :payment_type_id, :presence => true
validates :payment_type_id, :inclusion => {:in => PAYMENT_TYPES}
end
Model payment_type.rb
class PaymentType < ActiveRecord::Base
attr_accessible :name, :id
has_many :order
end
From browser, validation works fine, if it is wrong it give an error, else go forward.
But problem is when I run rake test:functionals from terminal. Test didn't pass the validation. If I comment this line:
validates :payment_type_id, :inclusion => {:in => PAYMENT_TYPES}
all is ok. I don't understand why it is working in one plase, but in tests not ? ...
Fixtures are all ok.
Please help.
Most likely the problem is, that you are storing your payment types in a constant.
For your tests to work, the PaymentTypes have to be available in the database before rails loads your Order model, and this might not be the case.
One way to get around this, would be to use a (memoized) class method to store your payment types. As long as you access this class method after all your PaymentTypes are in the database, you should be fine.
class Order < ActiveRecord::Base
validates :payment_type_id, :inclusion => { :in => self.payment_types }
def self.payment_types
##payment_types ||= PaymentType.pluck(:id)
end
end
I have a sentence and correction model with a has_one and belongs_to relationship respectively.
For some reason when I do
def create
#sentence = Sentence.find(params[:sentence_id])
#correction = #sentence.build_correction(params[:correction])
a custom validation I wrote for Correction is being called at the build_correction point. the validation is below
class Correction < ActiveRecord::Base
attr_accessible :text, :sentence_id, :user_id
belongs_to :sentence
belongs_to :user
validate :correction_is_different_than_sentence
def correction_is_different_than_sentence
errors.add(:text, "can't be the same as the original sentence.") if (text == self.sentence.text)
end
the problem is for some reason on validation the correction object doesn't have the sentence id set (despite I used the build_correction method) and so it complains
"you have nil object .... while executing nil.text" in the if clause in the validation above.
So my question is why is the validation occuring for a build command, i thought it only triggers on a create or update. And why isnt the sentence_id getting set?
Some error was creating a lot of headaches for me. Don't know why but moving custom validator call to the end of other validator calls fixed this for me.
Before
validates :name, :short_description, presence: true
validate :uniq_name
validates :price, :numericality => {:greater_than_or_equal_to => 0}
validates_attachment_content_type :image, :content_type => /image/
After
validates :name, :short_description, presence: true
validates :price, :numericality => {:greater_than_or_equal_to => 0}
validates_attachment_content_type :image, :content_type => /image/
validate :uniq_name
here is my custom validator
private
def uniq_name
return if clone?
user_product = self.user.products.unlocked.where(:name => self.name).first
errors[:name] << "has already been taken" if user_product && !user_product.id.eql?(self.id)
end
Try this, may be it will do the trick for you too.
As ever it was not rails fault but my own - its trivial, long to explain, no use to anyone else so wont explain.