The Depot Application

The Depot Application

15 Rails In Depth 14.4 Integration Testing of Applications

14.5 Performance Testing

mkdir test/fixtures/performance/
edit test/fixtures/performance/products.yml
<% 1.upto(1000) do |i| %>
product_<%= i %>:
  id: <%= i %>
  title: Product Number <%= i %>
  description: My description
  image_url: product.gif
  price: 1234
<% end %>
edit test/performance/order_speed_test.rb
require 'test_helper'
require 'store_controller'
 
class OrderSpeedTest < ActionController::TestCase
  tests StoreController
  
  DAVES_DETAILS = {
      :name     => "Dave Thomas",
      :address  => "123 The Street",
      :email    => "dave@example.com",
      :pay_type => "check"
  }
  
  self.fixture_path = File.join(File.dirname(__FILE__), "../fixtures/performance")
  fixtures :products
  
 
  def test_100_orders
    Order.delete_all
    LineItem.delete_all
 
    @controller.logger.silence do
      elapsed_time = Benchmark.realtime do
        100.downto(1) do |prd_id|
          cart = Cart.new
          cart.add_product(Product.find(prd_id))
          post :save_order, 
               { :order => DAVES_DETAILS },
               { :cart  => cart }
          assert_redirected_to :action => :index
        end         
      end       
      assert_equal 100, Order.count
      assert elapsed_time < 3.00
    end
  end
end
ruby -I test test/performance/order_speed_test.rb
Loaded suite test/performance/order_speed_test
Started
E
 
Error:
test_100_orders(OrderSpeedTest):
FixturesFileNotFound: Could not find test/performance/../fixtures/performance/orders.yml or test/performance/../fixtures/performance/orders.csv
 
 
 
 
Finished in 0.075971554 seconds.
 
1 tests, 0 assertions, 0 failures, 1 errors, 0 pendings, 0 omissions, 0 notifications
0% passed
 
13.16 tests/s, 0.00 assertions/s
edit app/models/user.rb
require 'digest/sha1'
 
class User < ActiveRecord::Base
  
  validates_presence_of     :name
  validates_uniqueness_of   :name
 
  attr_accessor :password_confirmation
  validates_confirmation_of :password
 
  validate :password_non_blank
  
  def self.authenticate(name, password)
    user = self.find_by_name(name)
    if user
      expected_password = encrypted_password(password, user.salt)
      if user.hashed_password != expected_password
        user = nil
      end
    end
    user
  end
  
  # 'password' is a virtual attribute
  def password
    @password
  end
  
  def password=(pwd)
    @password = pwd
    return if pwd.blank?
    create_new_salt
    self.hashed_password = User.encrypted_password(self.password, self.salt)
  end
  
  after_destroy :ensure_an_admin_remains
 
  def ensure_an_admin_remains
    if User.count.zero?
      raise "Can't delete last user"
    end
  end     
 
private
 
  def password_non_blank
    errors.add(:password, "Missing password") if hashed_password.blank?
  end
  
  def create_new_salt
    self.salt = self.object_id.to_s + rand.to_s
  end
  
  def self.encrypted_password(password, salt)
    100000.times { Math.sin(1)}
    string_to_hash = password + "wibble" + salt
    Digest::SHA1.hexdigest(string_to_hash)
  end
end
rails benchmarker "User.encrypted_password(\"secret\", \"salt\")"
            user     system      total        real
#1      0.160000   0.020000   0.180000 (  0.199111)
rails profiler "User.encrypted_password(\"secret\", \"salt\")"
Using the standard Ruby profiler.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 43.02     2.25      2.25        1  2250.00  5150.00  Integer#times
 38.24     4.25      2.00   100000     0.02     0.03  Math.sin
 17.21     5.15      0.90   100000     0.01     0.01  Fixnum#to_f
  0.76     5.19      0.04       24     1.67     1.67  Kernel.respond_to?
  0.19     5.20      0.01        2     5.00    45.00  ActiveSupport::Dependencies.new_constants_in
  0.19     5.21      0.01       11     0.91     0.91  ActiveSupport::Callbacks::Callback#start
  0.19     5.22      0.01        6     1.67     1.67  Hash#extractable_options?
  0.19     5.23      0.01      897     0.01     0.01  Symbol#to_s
  0.00     5.23      0.00        1     0.00     0.00  String#intern
  0.00     5.23      0.00       11     0.00     0.00  Array#first
  0.00     5.23      0.00        6     0.00     0.00  String#empty?
  0.00     5.23      0.00       13     0.00     0.00  Module#const_defined?
  0.00     5.23      0.00       12     0.00     0.00  Module#const_get
  0.00     5.23      0.00       49     0.00     3.27  Array#each
  0.00     5.23      0.00        6     0.00     0.00  ActiveSupport::Inflector.constantize
  0.00     5.23      0.00        9     0.00     0.00  ActiveSupport::Dependencies.logger
  0.00     5.23      0.00        5     0.00     0.00  ActiveSupport::Dependencies.log_call
  0.00     5.23      0.00        6     0.00     0.00  String#sub
  0.00     5.23      0.00        7     0.00     0.00  ActiveSupport::Dependencies.local_const_defined?
  0.00     5.23      0.00       11     0.00     0.00  Enumerable.inject
  0.00     5.23      0.00        5     0.00     0.00  ActiveSupport::Dependencies.qualified_const_defined?
  0.00     5.23      0.00        2     0.00     0.00  BasicObject#equal?
  0.00     5.23      0.00       29     0.00     0.00  Module#===
  0.00     5.23      0.00        3     0.00     0.00  String#=~
  0.00     5.23      0.00        3     0.00     0.00  Kernel.!~
  0.00     5.23      0.00        3     0.00     0.00  String#blank?
  0.00     5.23      0.00        3     0.00     0.00  ActiveSupport::Dependencies.to_constant_name
  0.00     5.23      0.00        5     0.00     0.00  Module#name
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.qualified_name_for
  0.00     5.23      0.00        1     0.00     0.00  String#initialize_copy
  0.00     5.23      0.00       17     0.00     0.00  Kernel.initialize_dup
  0.00     5.23      0.00       13     0.00     0.00  Kernel.dup
  0.00     5.23      0.00        3     0.00     0.00  String#gsub!
  0.00     5.23      0.00        1     0.00     0.00  String#tr!
  0.00     5.23      0.00        1     0.00     0.00  String#downcase!
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Inflector.underscore
  0.00     5.23      0.00        1     0.00     0.00  String#underscore
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::Dependencies.autoload_paths
  0.00     5.23      0.00        3     0.00     0.00  File#join
  0.00     5.23      0.00        3     0.00     0.00  File#file?
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.search_for_file
  0.00     5.23      0.00        3     0.00     0.00  ActiveSupport::Dependencies.loaded
  0.00     5.23      0.00        7     0.00     0.00  File#expand_path
  0.00     5.23      0.00        2     0.00     0.00  Hash#include?
  0.00     5.23      0.00        2     0.00     0.00  Set#include?
  0.00     5.23      0.00       32     0.00     0.00  Hash#[]=
  0.00     5.23      0.00        2     0.00     0.00  Set#add
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::Dependencies.mechanism
  0.00     5.23      0.00      503     0.00     0.00  Symbol#==
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::Dependencies.load?
  0.00     5.23      0.00        4     0.00     0.00  ActiveSupport::Dependencies.log
  0.00     5.23      0.00       21     0.00     0.00  NilClass#nil?
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.warnings_on_first_load
  0.00     5.23      0.00        4     0.00     0.00  Regexp#escape
  0.00     5.23      0.00        4     0.00     0.00  Regexp#=~
  0.00     5.23      0.00        3     0.00     0.00  String#[]
  0.00     5.23      0.00        2     0.00     0.00  String#gsub
  0.00     5.23      0.00        1     0.00     0.00  String#upcase
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Inflector.camelize
  0.00     5.23      0.00        1     0.00     0.00  String#camelize
  0.00     5.23      0.00        2     0.00     0.00  Array#uniq!
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.loadable_constants_for_path
  0.00     5.23      0.00       22     0.00     0.00  Kernel.is_a?
  0.00     5.23      0.00        1     0.00     0.00  Array#collect
  0.00     5.23      0.00        4     0.00     0.00  ActiveSupport::Dependencies.constant_watch_stack
  0.00     5.23      0.00        4     0.00     0.00  Module#constants
  0.00     5.23      0.00        4     0.00     0.00  Module#local_constants
  0.00     5.23      0.00       16     0.00     1.25  Array#map
  0.00     5.23      0.00        4     0.00     2.50  Module#local_constant_names
  0.00     5.23      0.00        8     0.00     0.00  Hash#[]
  0.00     5.23      0.00        2     0.00     5.00  ActiveSupport::Dependencies::WatchStack#watch_namespaces
  0.00     5.23      0.00        2     0.00     0.00  IO#set_encoding
  0.00     5.23      0.00      132     0.00     0.00  Hash#default
  0.00     5.23      0.00        1     0.00     0.00  Kernel.require
  0.00     5.23      0.00       26     0.00     0.00  Array#last
  0.00     5.23      0.00        3     0.00     0.00  Array#-
  0.00     5.23      0.00        6     0.00     0.00  Array#concat
  0.00     5.23      0.00       15     0.00     0.00  Array#pop
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::Dependencies::WatchStack#pop_modules
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::Dependencies::WatchStack#new_constants
  0.00     5.23      0.00        3     0.00     0.00  Array#*
  0.00     5.23      0.00       11     0.00     0.00  String#split
  0.00     5.23      0.00        1     0.00     0.00  Array#blank?
  0.00     5.23      0.00        1     0.00    10.00  ActiveSupport::Dependencies::Loadable.load_dependency
  0.00     5.23      0.00        1     0.00    10.00  ActiveSupport::Dependencies::Loadable.require
  0.00     5.23      0.00       11     0.00     0.00  Hash#initialize_copy
  0.00     5.23      0.00        2     0.00     0.00  Hash#each
  0.00     5.23      0.00        1     0.00     0.00  Kernel.singleton_class
  0.00     5.23      0.00        1     0.00     0.00  Exception#initialize
  0.00     5.23      0.00        1     0.00     0.00  NameError#initialize
  0.00     5.23      0.00        1     0.00     0.00  Exception#exception
  0.00     5.23      0.00        1     0.00     0.00  Exception#backtrace
  0.00     5.23      0.00        1     0.00     0.00  Exception#set_backtrace
  0.00     5.23      0.00        1     0.00     0.00  Module#remove_method
  0.00     5.23      0.00        1     0.00     0.00  Module#remove_possible_method
  0.00     5.23      0.00        3     0.00     0.00  BasicObject#singleton_method_added
  0.00     5.23      0.00        4     0.00     0.00  Module#define_method
  0.00     5.23      0.00       14     0.00     0.00  Module#class_eval
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::Base#_validators=
  0.00     5.23      0.00        7     0.00     0.00  Kernel.hash
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::DescendantsTracker.direct_descendants
  0.00     5.23      0.00        3     0.00     0.00  Regexp#===
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::DynamicFinderMatch#match
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::DynamicScopeMatch#match
  0.00     5.23      0.00       20     0.00     0.00  Kernel.respond_to_missing?
  0.00     5.23      0.00        1     0.00     0.00  String#scan
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::Base#respond_to?
  0.00     5.23      0.00        2     0.00     0.00  Class#inheritable_attributes
  0.00     5.23      0.00        6     0.00     0.00  Object#duplicable?
  0.00     5.23      0.00        5     0.00     0.00  Array#initialize_copy
  0.00     5.23      0.00        5     0.00     0.00  Hash#update
  0.00     5.23      0.00        1     0.00     0.00  TrueClass#duplicable?
  0.00     5.23      0.00        1     0.00     0.00  Kernel.instance_variable_set
  0.00     5.23      0.00        1     0.00     0.00  Class#inherited_with_inheritable_attributes
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::DescendantsTracker.inherited
  0.00     5.23      0.00        1     0.00     0.00  ActiveModel::Validations::ClassMethods.inherited
  0.00     5.23      0.00        1     0.00     0.00  ActiveModel::Observing::ClassMethods.notify_observers
  0.00     5.23      0.00        1     0.00     0.00  ActiveModel::Observing::ClassMethods.inherited
  0.00     5.23      0.00        2     0.00     0.00  WillPaginate::PerPage.per_page
  0.00     5.23      0.00        1     0.00     0.00  Integer#to_i
  0.00     5.23      0.00        1     0.00     0.00  WillPaginate::PerPage.per_page=
  0.00     5.23      0.00        1     0.00     0.00  WillPaginate::PerPage::Inheritance.inherited
  0.00     5.23      0.00       11     0.00     0.91  Array#extract_options!
  0.00     5.23      0.00        4     0.00     0.00  Array#flatten
  0.00     5.23      0.00        4     0.00     0.00  Hash#merge
  0.00     5.23      0.00        3     0.00     0.00  ActiveModel::Validations::HelperMethods._merge_attributes
  0.00     5.23      0.00        6     0.00     0.00  Kernel.instance_of?
  0.00     5.23      0.00        2     0.00     0.00  Array#unshift
  0.00     5.23      0.00        8     0.00     0.00  Hash#delete
  0.00     5.23      0.00       10     0.00     0.00  Kernel.nil?
  0.00     5.23      0.00        5     0.00     0.00  Array#to_ary
  0.00     5.23      0.00       28     0.00     1.43  Array#wrap
  0.00     5.23      0.00        3     0.00     0.00  Kernel.freeze
  0.00     5.23      0.00        3     0.00     0.00  ActiveModel::Validator#initialize
  0.00     5.23      0.00        3     0.00     0.00  ActiveModel::EachValidator#check_validity!
  0.00     5.23      0.00        3     0.00    13.33  ActiveModel::EachValidator#initialize
  0.00     5.23      0.00        8     0.00     5.00  Class#new
  0.00     5.23      0.00       26     0.00     0.00  Symbol#to_sym
  0.00     5.23      0.00        3     0.00     0.00  Proc#yield
  0.00     5.23      0.00        4     0.00     0.00  Hash#key?
  0.00     5.23      0.00       28     0.00     0.00  Array#include?
  0.00     5.23      0.00        5     0.00     0.00  ActiveSupport::DescendantsTracker.descendants
  0.00     5.23      0.00       12     0.00     0.00  Kernel.object_id
  0.00     5.23      0.00        2     0.00     0.00  Class#superclass
  0.00     5.23      0.00        9     0.00     0.00  ActiveRecord::Base#_validate_callbacks
  0.00     5.23      0.00        5     0.00     0.00  ActiveSupport::Callbacks::Callback#normalize_options!
  0.00     5.23      0.00       12     0.00     0.00  ActiveSupport::Callbacks::Callback#next_id
  0.00     5.23      0.00       12     0.00     0.00  Fixnum#to_s
  0.00     5.23      0.00       23     0.00     0.00  Object#blank_slate_method_added
  0.00     5.23      0.00       23     0.00     0.00  Object#method_added
  0.00     5.23      0.00       23     0.00     0.00  ActiveRecord::Callbacks::ClassMethods.method_added
  0.00     5.23      0.00        3     0.00     0.00  ActiveSupport::Callbacks::Callback#_normalize_legacy_filter
  0.00     5.23      0.00        3     0.00     0.00  ActiveSupport::Callbacks::Callback#name
  0.00     5.23      0.00       21     0.00     0.00  Array#join
  0.00     5.23      0.00        7     0.00     0.00  ActiveSupport::Callbacks::Callback#_compile_filter
  0.00     5.23      0.00       10     0.00     0.00  ActiveSupport::Callbacks::Callback#_compile_options
  0.00     5.23      0.00        5     0.00     0.00  NilClass#to_s
  0.00     5.23      0.00        5     0.00     0.00  ActiveSupport::Callbacks::Callback#_compile_per_key_options
  0.00     5.23      0.00        5     0.00     0.00  ActiveSupport::Callbacks::Callback#initialize
  0.00     5.23      0.00        5     0.00     0.00  Array#delete_if
  0.00     5.23      0.00        4     0.00     0.00  Array#push
  0.00     5.23      0.00       17     0.00     0.00  Array#compact
  0.00     5.23      0.00        8     0.00     0.00  String#to_s
  0.00     5.23      0.00       11     0.00     0.00  ActiveSupport::Callbacks::Callback#end
  0.00     5.23      0.00        5     0.00     0.00  Array#reverse_each
  0.00     5.23      0.00        5     0.00     2.00  ActiveSupport::Callbacks::CallbackChain#compile
  0.00     5.23      0.00        6     0.00     0.00  Module#method_defined?
  0.00     5.23      0.00        6     0.00     0.00  Module#private
  0.00     5.23      0.00        5     0.00     0.00  Kernel.with_warnings
  0.00     5.23      0.00        5     0.00     0.00  Kernel.silence_warnings
  0.00     5.23      0.00        5     0.00     2.00  ActiveSupport::Callbacks::ClassMethods.__define_runner
  0.00     5.23      0.00        5     0.00     2.00  ActiveSupport::Callbacks::ClassMethods.__update_callbacks
  0.00     5.23      0.00        5     0.00     2.00  ActiveSupport::Callbacks::ClassMethods.set_callback
  0.00     5.23      0.00        4     0.00     5.00  ActiveModel::Validations::ClassMethods.validate
  0.00     5.23      0.00        3     0.00    20.00  ActiveModel::Validations::ClassMethods.validates_with
  0.00     5.23      0.00        1     0.00    10.00  ActiveModel::Validations::HelperMethods.validates_presence_of
  0.00     5.23      0.00        1     0.00     0.00  Hash#reverse_merge
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::Validations::UniquenessValidator#initialize
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::Validations::UniquenessValidator#setup
  0.00     5.23      0.00        6     0.00     0.00  String#==
  0.00     5.23      0.00        6     0.00     0.00  ActiveSupport::Callbacks::Callback#matches?
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::Validations::ClassMethods.validates_uniqueness_of
  0.00     5.23      0.00        2     0.00     0.00  Module#attr_accessor
  0.00     5.23      0.00       34     0.00     0.00  Array#empty?
  0.00     5.23      0.00        1     0.00     0.00  ActiveModel::Validations::ConfirmationValidator#setup
  0.00     5.23      0.00        1     0.00    50.00  ActiveModel::Validations::HelperMethods.validates_confirmation_of
  0.00     5.23      0.00        1     0.00     0.00  Array#shift
  0.00     5.23      0.00        3     0.00     0.00  ActiveRecord::Base#_destroy_callbacks
  0.00     5.23      0.00        1     0.00     0.00  Array#reverse
  0.00     5.23      0.00        1     0.00     0.00  ActiveRecord::Base#after_destroy
  0.00     5.23      0.00        1     0.00    70.00  Kernel.load
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.autoload_once_paths
  0.00     5.23      0.00        1     0.00     0.00  Enumerable.any?
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.load_once_path?
  0.00     5.23      0.00        2     0.00     0.00  ActiveSupport::Dependencies.autoloaded_constants
  0.00     5.23      0.00        1     0.00    80.00  ActiveSupport::Dependencies.load_file
  0.00     5.23      0.00        1     0.00     0.00  ActiveSupport::Dependencies.history
  0.00     5.23      0.00        1     0.00    80.00  ActiveSupport::Dependencies.require_or_load
  0.00     5.23      0.00        1     0.00    80.00  ActiveSupport::Dependencies.load_missing_constant
  0.00     5.23      0.00        4     0.00     0.00  Object#presence
  0.00     5.23      0.00        4     0.00     0.00  Object#present?
  0.00     5.23      0.00        1     0.00     0.00  NilClass#blank?
  0.00     5.23      0.00        1     0.00     0.00  BasicObject#initialize
  0.00     5.23      0.00        2     0.00     0.00  Digest::Base#reset
  0.00     5.23      0.00        1     0.00     0.00  Digest::Base#update
  0.00     5.23      0.00        1     0.00     0.00  Digest::Base#finish
  0.00     5.23      0.00        1     0.00     0.00  Digest::Instance.digest
  0.00     5.23      0.00        1     0.00     0.00  Digest::Class#digest
  0.00     5.23      0.00        1     0.00     0.00  Digest::Class#hexdigest
  0.00     5.23      0.00        1     0.00  5150.00  User#encrypted_password
  0.00     5.23      0.00        1     0.00  5230.00  Object#profile_me
  0.00     5.23      0.00        1     0.00  5230.00  #toplevel
edit app/models/user.rb

15 Rails In Depth 14.4 Integration Testing of Applications