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 :price, numericality: {greater_than_or_equal_to: 0.01}
  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

4 errors prohibited this product from being saved:

  • Title can't be blank
  • Description can't be blank
  • Image url can't be blank
  • Price must be greater than or equal to 0.01
Back

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 :price, numericality: {greater_than_or_equal_to: 0.01}
  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

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

rails test
/home/rubys/.rvm/gems/ruby-2.4.0/gems/sass-3.4.23/lib/sass/util.rb:1109: warning: constant ::Fixnum is deprecated
Run options: --seed 50140
 
# Running:
 
..F
 
Failure:
ProductsControllerTest#test_should_create_product [/home/rubys/git/awdwr/edition4/work-240/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
 
F
 
Failure:
ProductsControllerTest#test_should_update_product [/home/rubys/git/awdwr/edition4/work-240/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.543621s, 12.8766 runs/s, 14.7161 assertions/s.
 
7 runs, 8 assertions, 2 failures, 0 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)
    @update = {
      title:       'Lorem Ipsum',
      description: 'Wibbles are fun!',
      image_url:   'lorem.jpg',
      price:       19.95
    }
  end
 
  test "should get index" do
    get products_url
    assert_response :success
  end
 
  test "should get new" do
    get new_product_url
    assert_response :success
  end
 
  test "should create product" do
    assert_difference('Product.count') do
      post products_url, params: { product: @update }
    end
 
    assert_redirected_to product_url(Product.last)
  end
 
  # ...
  test "should update product" do
    patch product_url(@product), params: { product: @update }
    assert_redirected_to product_url(@product)
  end
 
  # ...
end

Tests now pass again :-)

rails test
Run options: --seed 57470
 
# Running:
 
.......
 
Finished in 0.243448s, 28.7535 runs/s, 36.9688 assertions/s.
 
7 runs, 9 assertions, 0 failures, 0 errors, 0 skips

7.2 Iteration B2: Unit Testing 6.3 Playtime