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
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.199402 seconds.
 
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
 
Test run options: --seed 49270
[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
F.....F
Finished in 0.345394 seconds.
 
  1) Failure:
test_should_create_product(ProductsControllerTest) [/home/rubys/git/awdwr/edition4/work-192-30/depot/test/functional/products_controller_test.rb:20]:
"Product.count" didn't change by 1.
<3> expected but was
<2>.
 
  2) Failure:
test_should_update_product(ProductsControllerTest) [/home/rubys/git/awdwr/edition4/work-192-30/depot/test/functional/products_controller_test.rb:39]:
Expected response to be a <:redirect>, but was <200>
 
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
 
Test run options: --seed 11882
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
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.204823 seconds.
 
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
 
Test run options: --seed 3307
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
[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.
.......
Finished in 0.381758 seconds.
 
7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
 
Test run options: --seed 3245

7.2 Iteration B2: Unit Testing 6.3 Playtime