Should native validations be tested in rails? - ruby-on-rails

Everybody knows that automated testing is a good thing.
Not everybody knows exacly what to test.
My question is if native validations like validate_presence_of, validate_uniqueness_of and so on should be tested in the application.
In my office we are three, one thinks it should be tested, one thinks it shouldn´t and I am up in the air.

Yes.
Testing that a model attribute is present or not is only testing the validates_presence_of code as a by-product of the real test which is that the validates_presence_of exists within your model.
If someone commented out a bunch of validation code and then forgot to uncomment it then this would go undetected and could cause all sorts of problems.
I test them, not because I think they don't work but to ensure that they are present in my model when required.

Are you planning to write unit tests for every single Ruby operator and API method as well?
Your unit tests should test your own code, not other people's - that's their job, why duplicate their work? And if you don't trust them to do their job well, why are you using their code?

Matthew Bass has a great gem he's released for just this type of thing. It adds rspec matchers that check to make sure the validation is in place without actually running the underlying ActiveRecord code. Read more about it here.
It adds matchers for validations:
it_should_validate_presence_of :first_name, :last_name, :email
it_should_validate_numericality_of :zip
it_should_validate_uniqueness_of :email
it_should_validate_inclusion_of :gender, :in => %w(Male Female)
Also matchers for associations:
it_should_belong_to :employer
it_should_have_many :friends, :romans, :countrymen
it_should_have_one :account
it_should_have_and_belong_to_many :comments
And a few other useful additions:
# tests that User.count increases by 1
it_should_be_createable :with => {:first_name => 'Ed', :last_name => 'The Duck', :email => 'a#b.com'}
# tests that the attribute is protected
it_should_protect :email
That's not by any means an exhaustive list. I've got a fork where I've added a few others I needed, likely there are others floating around as well. It's a good approach and for me fit the middle ground between ensuring the validations were still in the model, and having to explicitly write tests to execute ActiveRecord code to ensure it.

This is where tools like Shoulda really come in handy. I think its totally up to you to test how you write the code with the tools people provide you. Just because you are using has_many, does not mean you are using it right!
Seriously, if you integrate Shoulda into the mix, it becomes trivial to test these sorts of things. if you run rcov, its going to tell you all the code you wrote is not fully tested, unless you do.

Test the code you write. ActiveRecord has great test coverage including coverage for the validation class methods.
Spec:
require 'spec_helper'
describe User do
before(:each) do
#user = User.new
end
it "should not be valid without an email" do
#user.save.should be_false
#user.should_not be_valid
#user.email = "example#example.com"
#user.should be_valid
#user.save.should be_true
end
end
To get that spec to pass you would need
class User < ActiveRecord::Base
validates_presence_of :email
end

Related

Where to use attr_accessor in Rails?

Why would you use attr_accessor in Rails?
Documentation: http://apidock.com/ruby/Module/attr_accessor
My understanding is that it can be used to create "transient" variables that are not persisted in the db. And that it's a substitute for manually writing a setter and a getter.
But I don't think other answer explain much more than above. Ie: Why use Ruby's attr_accessor, attr_reader and attr_writer?
So I'm still not sure in what situation I would actually use it. Can anyone elaborate?
If by "in rails" you mean "activerecord models", then your guess is correct: transient attributes.
Here's an example (a bit contrived):
class User < ActiveRecord::Base
attr_accessor :is_admin
validate_presence_of :name, :shipping_address, :billing_address, unless: :is_admin
end
Users created via regular flow (signup page) will refuse to get saved unless you provide all of the info. But there's a simpler flow for creating admins:
User.create(email: 'chris#example.com', is_admin: true)
# you do this in rails console or rake task, for example
Naturally, you should not accept this "private" flag from html forms (strong_params method in your controller).
Thinking a bit more about this example: you possibly want to store this flag in the database (is user admin or not). But I hope this should illustrate the idea anyway.

testing field type a model in mongoid

i use ruby on rails. also i use minitest framework for testing and mongoid for database. i want to write a model test. my model is below:
class Identity
include Mongoid::Document
include OmniAuth::Identity::Models::Mongoid
field :name
field :email
field :password_digest
validates :name, uniqueness: true
end
the model test is:
describe Identity do
it "must include OmniAuth::Identity::Models::Mongoid" do
Identity.must_include OmniAuth::Identity::Models::Mongoid
end
it "should have name" do
Identity.new.must_respond_to :name
end
it "should have email" do
Identity.new.must_respond_to :email
end
it "should have password_digest" do
Identity.new.must_respond_to :password_digest
end
it "should type of String" do
Identity.new.name.type.must_equal "String"
end
end
my problem is about testing the field's type
it "should type of String" do
Identity.new.name.type.must_equal "String"
end
How can i test a field's type? Thanks in advance.
Just a tip - while not an answer to your actual question, it is usually not that
wise test implementation details of code, because it is more likely
to change, and if you think of system validation through tests, it is not that important
how it is implemented, but what it does, eg. how it behaves.
A canonical example is that of testing functionality of a Stack class. Instead of
pushing and popping items out of stack and checking the size, it is likely better to
just push and pop things, and see that if you pop an empty stack, you get appropriate
exception. And naturally you want to check that items are returned in last in, first out
(LIFO) order.
So, in your case, instead of testing what kind of type your field name is, rather
test what you do with the name.

Is there a Lint for ActiveRecord?

Rubyists, particularly Railsers, know all about ActiveModel::Lint, which is a handy way to ensure that you haven't cocked up when writing your ActiveModel subclass, and saves hours of head-scratching. I use it all the time for table-less models in Rails projects.
But I spend a lot of time hunting down errors with my usage of ActiveRecord - particularly with double-sided associations. For example
# app/models/blog.rb
class Blog < ActiveRecord::Base
has_many :posts # so far so good...
end
# app/models/post.rb
class Post < ActiveRecord::Base
has_one :blog # incorrect - should be belongs_to
end
That example is somewhat contrived, as nobody's that silly. But what if Blog actually has a post_id column? Exceptions would not be raised where expected.
I'd like to be able to write a test for Blog like this
# test/unit/blog_test.rb
require 'test/test_helper'
class BlogTest < ActiveSupport::TestCase
include ActiveRecord::Lint
end
...and the test output should say something like Blog :has_many :posts, but Post does not :belong_to :blog!. It would need to reflect on the associations, dealing with table-names, foreign-keys, etc, and considering :through models on the way. I know that proper unit tests will detect these issues anyway, but generally as side-effects of other tests.
Does anyone know of a project which does this? (I'm only interested in ActiveRecord >= 3.1). All I could find was active_record_lint, which doesn't really do this at all.
Additionally, it would be great if all the existing fixtures could be tested automatically, to make sure that those pesky associations are set up. I usually just do
test "fixtures" do
Post.all.each { |p| assert p.valid? "Fixture is broken! #{p.inspect}" }
end
but there's surely a more elegant way.
A tool like this would be useful, but you should be testing these things explicitly anyway. This will uncover problems like this immediately. For instance, a typical unit test:
def test_defaults
blog = Blog.create(
:title => 'Example Blog'
)
assert blog.valid?
assert_equal [ ], blog.errors.full_messages
assert !blog.new_record?
assert_equal 0, blog.posts.count
end
For your post:
def test_defaults
blog = Blog.create(
:title => 'Example Blog'
)
post = Post.create(
:blog => blog,
:content => 'Blogging blog bloggers blogged blogs'
)
assert post.valid?
assert_equal [ ], post.errors.full_messages
assert !post.new_record?
assert_equal blog.id, post.blog_id
assert_equal 1, blog.posts.count
end
Those are the long form versions of some helper methods that I usually use.
If you don't exercise the relationships, you're not testing them and you've got a problem with your test coverage. If you exercise a bad relationship it will show up as an error.

What "validation logic" should I test?

I am using Ruby on Rails 3.0.9 and RSpec 2. I would like to know what "validation logic" I should test. That is, if in my model I have:
class User < ActiveRecord::Base
validates :firstname
:presence => true
end
What should I test of the following?
"should have a valid first name"
"should not have a valid first name"
Or should I test both?
You can test both by simply doing this:
it "should validate presence of" do
should validate_presence_of :firstname
end
Take a look at the shoulda matchers for all such standard Rails Validation.
I think you should not test both. This will be enough:
describe User do
it { should validate_presence_of(:firstname) }
end
There is basically no algorithm for validating names, because the form of names is incredibly culture-centric. So, really you should avoid complex validations for something like a person's name. Some places/cultures don't have last names, for example, so even validating their presence isn't proper. There's a whole list of other examples that make validating names a really bad idea. For more information on the issue of validating names itself, see my answer to this question.
That being said, in general, when validating any field, I test both valid and invalid data. I make sure that, when I set a field to a valid value, that the .valid? method returns true, and when it's invalid, that it returns false.
Typically you don't need to do a long list, you just need to test
A typical valid and invalid example
A few edge cases
you can also test for specific values:
describe User do
context "validations" do
it { should_not allow_value("admin").for(:firstname) }
it { should allow_value("JohnDoe").for(:firstname) }
end
end

Railstutorial.org Validating presence tests

I've been working through the tutorials at railstutorial.org, and I was a little stumped by the author's code for section -- 6.2.1 Validating presence.
In the user model, the tutorial adds validates :name, :presence => true. Simple enough.
When the author chooses to write the rspec test, he does something that I thought was a little strange.
describe User do
before(:each) do
#attr = { :name => "Example User", :email => "user#example.com" }
end
.
.
.
it "should require a name" do
no_name_user = User.new(#attr.merge(:name => ""))
no_name_user.should_not be_valid
end
end
Why go through the trouble to merge a blank string to #attr when one could get rid of the :each block statement and simply write:
it "should require a name" do
no_name_user = User.new(:name => "", :email => "user#example.com")
no_name_user.should_not be_valid
end
I know that the author uses the #attr variable to validate the presence of the email address as well, which is one indication as to why he used the block statement -- to me it makes more sense to follow the structure of the second block quote. Still, I have a feeling there is something that I'm missing here.
Another explanation that crossed my mind is that it helps to use the #attr structure when there are lots of keys to be entered, as opposed to this rather simplistic case of only name and email.
Anyone have any input?
It's so there's one standard attributes map that can be used across all the tests. When a test requires that a value isn't there, it's removed.
Personally, I wasn't convinced it was worth it as it sort of obfuscates things (as you discovered), but there it is.
The point is to only have code relevant for the test case in the test. The only relevant attribute when testing that the user isn't valid without a name is the name attribute. That test should not have to know anything about the email attribute.
Let's say you add validation for the presence of a new field – you'd have to update every test where you build up a User without that field. With the attr hash at the top, you just pop the new field in there, and all your tests are fine.
Creating objects for testing is a common enough problem that there are many solutions, and plenty of discussion about which way is best. I'd suggest you look into factories. Machinist and FactoryGirl are two alternatives that work great with Rails.

Resources