Agile Web Development with Rails, Edition 5

7.2 Iteration B2: Unit Testing 6.3 Playtime

7.1 Iteration B1: Validation and Unit Testing

Augment the model with a few vailidity checks.

Various validations: required, numeric, positive, and unique

edit app/models/product.rb
class Product < ApplicationRecord
  validates :title, :description, :image_url, presence: true
  validates :title, 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

Demonstrate failures.

get /products/new

New Product

Back
post /products

New Product

3 errors prohibited this product from being saved:

  • Title can't be blank
  • Description can't be blank
  • Image url can't be blank
Back

Add price validations

edit app/models/product.rb
class Product < ApplicationRecord
  validates :title, :description, :image_url, presence: true
  validates :title, 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.'
  }
  validates :price, numericality: { greater_than_or_equal_to: 0.01 }
 
end

Demonstrate more failures.

get /products/new

New Product

Back
post /products

New Product

1 error prohibited this product from being saved:

  • Price is not a number
Back
edit app/models/product.rb
class Product < ApplicationRecord
  validates :title, :description, :image_url, presence: true
  validates :title, 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.'
  }
  validates :price, numericality: { greater_than_or_equal_to: 0.01 }
 
end

Now run the tests... and watch them fail :-(

rails test
Run options: --seed 4530
 
# Running:
 
F
 
Failure:
ProductsControllerTest#test_should_create_product [/home/rubys/git/awdwr/edition4/work/depot/test/controllers/products_controller_test.rb:19]:
"Product.count" didn't change by 1.
Expected: 3
  Actual: 2
 
bin/rails test test/controllers/products_controller_test.rb:18
 
E
 
Error:
ProductsControllerTest#test_should_get_index:
ActionView::Template::Error: The asset "MyString" is not present in the asset pipeline.
    app/views/products/index.html.erb:20:in `block in _app_views_products_index_html_erb__2013060306156878397_60937180'
    app/views/products/index.html.erb:16:in `_app_views_products_index_html_erb__2013060306156878397_60937180'
    test/controllers/products_controller_test.rb:9:in `block in <class:ProductsControllerTest>'
 
bin/rails test test/controllers/products_controller_test.rb:8
 
F
 
Failure:
ProductsControllerTest#test_should_update_product [/home/rubys/git/awdwr/edition4/work/depot/test/controllers/products_controller_test.rb:38]:
Expected response to be a <3XX: redirect>, but was a <200: OK>
 
bin/rails test test/controllers/products_controller_test.rb:36
 
....
 
Finished in 0.306594s, 22.8315 runs/s, 22.8315 assertions/s.
7 runs, 7 assertions, 2 failures, 1 errors, 0 skips

Solution is simple, provide valid data.

edit test/controllers/products_controller_test.rb
require 'test_helper'
 
class ProductsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @product = products(:one)
    @title = "The Great Book #{rand(1000)}"
 
  end
 
  

Onto the next failure...

rails test
Run options: --seed 27223
 
# Running:
 
..F
 
Failure:
ProductsControllerTest#test_should_update_product [/home/rubys/git/awdwr/edition4/work/depot/test/controllers/products_controller_test.rb:73]:
Expected response to be a <3XX: redirect>, but was a <200: OK>
 
bin/rails test test/controllers/products_controller_test.rb:60
 
F
 
Failure:
ProductsControllerTest#test_should_create_product [/home/rubys/git/awdwr/edition4/work/depot/test/controllers/products_controller_test.rb:28]:
"Product.count" didn't change by 1.
Expected: 3
  Actual: 2
 
bin/rails test test/controllers/products_controller_test.rb:27
 
E
 
Error:
ProductsControllerTest#test_should_get_index:
ActionView::Template::Error: The asset "MyString" is not present in the asset pipeline.
    app/views/products/index.html.erb:20:in `block in _app_views_products_index_html_erb__1123884172246294594_51281100'
    app/views/products/index.html.erb:16:in `_app_views_products_index_html_erb__1123884172246294594_51281100'
    test/controllers/products_controller_test.rb:16:in `block in <class:ProductsControllerTest>'
 
bin/rails test test/controllers/products_controller_test.rb:15
 
..
 
Finished in 0.263985s, 26.5166 runs/s, 26.5166 assertions/s.
7 runs, 7 assertions, 2 failures, 1 errors, 0 skips

Update test data

edit test/fixtures/products.yml
# Read about fixtures at
# http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
 
one:
  title: MyString
  description: MyText
  image_url: lorem.jpg
  price: 9.99
 
two:
  title: MyString
  description: MyText
  image_url: lorem.jpg
  price: 9.99

Tests now pass again :-)

rails test
Run options: --seed 63365
 
# Running:
 
.......
 
Finished in 0.207170s, 33.7886 runs/s, 43.4425 assertions/s.
7 runs, 9 assertions, 0 failures, 0 errors, 0 skips

7.2 Iteration B2: Unit Testing 6.3 Playtime