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:

  1. Tests should be reliable
  2. Tests should be easy to write
  3. 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:

  1. We are not focusing on speed in our tests
  2. 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.4.4"
  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:

  1. rspec-rails is RSpec with extra Rails-specific features
  2. factory_bot_rails enables us to create test data with ease
  3. faker generates names, email addresses, and other placeholders for factories
  4. capybara is used to programatically simulate user input
  5. database_cleaner makes sure each spec run in our RSpec begins with a clean slate
  6. launchy can open your default web browser on demand to show you what your app is rendering
  7. 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

[Go-Jek x BNCC] Validation and Unit Testing

By qblfrb

[Go-Jek x BNCC] Validation and Unit Testing

  • 400