Agile Web Development with Rails, Edition 4

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 < ActiveRecord::Base
  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 < ActiveRecord::Base
  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 :-(

rake test
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
 
Finished in 0.002210 seconds.
 
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
 
ProductsControllerTest:
     FAIL should create product (0.28s) 
          "Product.count" didn't change by 1.
<3> expected but was
<2>.
          /home/rubys/git/rails/activesupport/lib/active_support/testing/assertions.rb:60:in `block in assert_difference'
 
     PASS should destroy product (0.00s) 
     PASS should get edit (0.01s) 
     PASS should get index (0.03s) 
     PASS should get new (0.01s) 
     PASS should show product (0.01s) 
     FAIL should update product (0.01s) 
          Expected response to be a <:redirect>, but was <200>
          /home/rubys/git/rails/actionpack/lib/action_dispatch/testing/assertions/response.rb:38:in `assert_response'
 
 
Finished in 0.354985 seconds.
 
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
Errors running test:functionals!

Solution is simple, provide valid data.

edit test/functional/products_controller_test.rb
require 'test_helper'
 
class ProductsControllerTest < ActionController::TestCase
  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 :index
    assert_response :success
    assert_not_nil assigns(:products)
  end
 
  test "should get new" do
    get :new
    assert_response :success
  end
 
  test "should create product" do
    assert_difference('Product.count') do
      post :create, product: @update
    end
 
    assert_redirected_to product_path(assigns(:product))
  end
 
  # ...
  test "should update product" do
    put :update, id: @product.to_param, product: @update
    assert_redirected_to product_path(assigns(:product))
  end
 
  # ...
end

Tests now pass again :-)

rake test
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
 
Finished in 0.002386 seconds.
 
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
 
ProductsControllerTest:
     PASS should create product (0.23s) 
     PASS should destroy product (0.01s) 
     PASS should get edit (0.04s) 
     PASS should get index (0.03s) 
     PASS should get new (0.01s) 
     PASS should show product (0.01s) 
     PASS should update product (0.01s) 
 
Finished in 0.334972 seconds.
 
7 tests, 10 assertions, 0 failures, 0 errors, 0 skips

7.2 Iteration B2: Unit Testing 6.3 Playtime