Validation
and Unit Testing
Validation
Remember our new/edit Food form?
Right now we can pretty much input anything in this form and it will process it anyway.
But we actually don't want, for instance, our "price" field is filled with non numeric inputs. Or, another example, we don't want user to forget to fill the "name" field.
Validating Presence
In Rails, we can enforce those rules by adding validations to our model. Here's some example:
class Food < ApplicationRecord
validates :name, :description, presence: true
end
In the example above, we validate our Food model by stating that it is mandatory to have the presence of fields "name" and "description".
Validating Numericality
Next, we want to make sure that only numeric values are filled in our "price" field.
class Food < ApplicationRecord
validates :name, :description, presence: true
validates :price, numericality: { greater_than_or_equal_to: 0.01 }
end
Validating Uniqueness
For now, we want to make sure that we don't input foods with the exact same name because it will confuse our users.
class Food < ApplicationRecord
validates :name, :description, presence: true
validates :price, numericality: { greater_than_equal_to: 0.01 }
validates :name, uniqueness: true
end
Validating Format
Lastly, we want to ensure that image_url is filled with URL that ends with either ".gif", ".jpg", or ".png".
class Food < ApplicationRecord
validates :name, :description, presence: true
validates :price, numericality: { greater_than_equal_to: 0.01 }
validates :name, uniqueness: true
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)\Z}i,
message: 'must be a URL for GIF, JPG or PNG image.'
}
end
Now you can play with our new/edit Food form to try how these validations work.
Unit Testing
TDD is Dead!
If you go around the internet, you will find a lot of debates about on how to test. DHH himself once said that "TDD is dead".
The Right Way to Test
So, not only there are many competing claims about what is the right way to use TDD in our development process, there is also the notion that TDD is not really the right way at all.
Given the circumstance, I want to highlight that for this course, we are focusing on three foundations when we do TDD:
- Tests should be reliable
- Tests should be easy to write
- Tests should be easy to understand
The Trade Offs
Like most decisions, focusing on the foundations we discussed above, there will be some trade-offs in this approach to TDD:
- We are not focusing on speed in our tests
- We are not focusing on overly DRY code in our tests
Setting Up
Remember RSpec? For the rest of this project, we will use RSpec for our unit testing. Now, let's set it up. Add these lines to your Gemfile:
# -cut-
group :development, :test do
# -cut-
gem 'rspec-rails', "~> 3.1.0"
gem 'factory_girl_rails', "~> 4.4.1"
end
group :test do
gem 'faker', "~> 1.4.3"
gem 'capybara', "~> 2.4.3"
gem 'database_cleaner', "~> 1.3.0"
gem 'launchy', "~> 2.4.2"
gem 'selenium-webdriver', "~> 2.43.0"
end
# -cut-
The Gems
Here are some sort explanations about the gems we just installed:
- rspec-rails is RSpec with extra Rails-specific features
- factory_girl enables us to create test data with ease
- faker generates names, email addresses, and other placeholders for factories
- capybara is used to programatically simulate user input
- database_cleaner makes sure each spec run in our RSpec begins with a clean slate
- launchy can open your default web browser on demand to show you what your app is rendering
- selenium-webdriver allows us to test Javascript-based interactions with capybara
Test Database
Don't forget to check if your test database is already defined in "config/database.yml" file. If not, you should set it up.
# -cut-
default: &default
adapter: sqlite3
pool: 5
timeout: 5000
# -cut-
test:
<<: *default
database: db/test.sqlite3
# -cut-
Generate RSpec Files
Now that everything is set and ready, fire this command in your console:
rails generate rspec:install
One Last Config
Lastly, modify your "config/application.rb" file:
class Application < Rails::Application
# -cut-
config.generators do |g|
g.test_framework :rspec,
fixtures: true,
view_specs: false,
helper_specs: false,
routing_specs: false,
controller_specs: true,
request_specs: false
g.fixture_replacement :factory_girl, dir: "spec/factories"
end
end
Validation and Unit Testing
By qblfrb
Validation and Unit Testing
- 315