15 Rails In Depth 14.4 Integration Testing of Applications
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.009523 seconds.
1 tests, 0 assertions, 0 failures, 1 errors, 0 pendings, 0 omissions, 0 notifications
0% passed
105.01 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.240000 0.000000 0.240000 ( 0.248684)
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
62.56 4.88 4.88 1 4880.00 7390.00 Integer#times
32.18 7.39 2.51 100000 0.03 0.03 Math.sin
1.28 7.49 0.10 4 25.00 25.00 Array#select
1.03 7.57 0.08 16 5.00 14.37 Array#map
1.03 7.65 0.08 73 1.10 11.37 Array#each
0.90 7.72 0.07 1 70.00 70.00 ActiveSupport::DescendantsTracker.inherited
0.26 7.74 0.02 14 1.43 1.43 Module#class_eval
0.26 7.76 0.02 5 4.00 6.00 ActiveSupport::Callbacks::CallbackChain#compile
0.26 7.78 0.02 881 0.02 0.02 String#to_s
0.13 7.79 0.01 5 2.00 2.00 Array#reverse_each
0.13 7.80 0.01 5 2.00 2.00 Kernel.with_warnings
0.00 7.80 0.00 2 0.00 0.00 ActiveSupport::DescendantsTracker.direct_descendants
0.00 7.80 0.00 1 0.00 0.00 Digest::Instance.digest
0.00 7.80 0.00 1 0.00 0.00 Digest::Base#finish
0.00 7.80 0.00 2 0.00 0.00 ActiveSupport::Dependencies.autoloaded_constants
0.00 7.80 0.00 1 0.00 0.00 String#upcase
0.00 7.80 0.00 11 0.00 0.00 ActiveSupport::Callbacks::Callback#end
0.00 7.80 0.00 3 0.00 0.00 Proc#call
0.00 7.80 0.00 3 0.00 0.00 ActiveModel::Validations::HelperMethods._merge_attributes
0.00 7.80 0.00 3 0.00 0.00 ActiveSupport::Dependencies.loaded
0.00 7.80 0.00 1 0.00 410.00 ActiveSupport::Dependencies.require_or_load
0.00 7.80 0.00 26 0.00 0.00 Symbol#to_sym
0.00 7.80 0.00 2 0.00 0.00 WillPaginate::PerPage.per_page
0.00 7.80 0.00 1 0.00 0.00 Array#blank?
0.00 7.80 0.00 2 0.00 55.00 ActiveSupport::Dependencies::WatchStack#watch_namespaces
0.00 7.80 0.00 1 0.00 0.00 Exception#set_backtrace
0.00 7.80 0.00 4 0.00 0.00 String#blank?
0.00 7.80 0.00 5 0.00 2.00 Kernel.silence_warnings
0.00 7.80 0.00 2 0.00 0.00 Set#include?
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Inflector.camelize
0.00 7.80 0.00 1 0.00 7800.00 Object#profile_me
0.00 7.80 0.00 6 0.00 0.00 Module#private
0.00 7.80 0.00 12 0.00 0.00 Fixnum#to_s
0.00 7.80 0.00 3 0.00 0.00 ActiveModel::Validator#initialize
0.00 7.80 0.00 47 0.00 0.00 Module#==
0.00 7.80 0.00 6 0.00 0.00 Array#concat
0.00 7.80 0.00 881 0.00 0.00 Hash#key?
0.00 7.80 0.00 12 0.00 0.00 ActiveSupport::Callbacks::Callback#next_id
0.00 7.80 0.00 13 0.00 0.00 Kernel.dup
0.00 7.80 0.00 2 0.00 0.00 ActiveSupport::Dependencies.autoload_paths
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Inflector.underscore
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.qualified_name_for
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::DynamicScopeMatch#match
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.warnings_on_first_load
0.00 7.80 0.00 23 0.00 0.00 Module#blank_slate_method_added
0.00 7.80 0.00 5 0.00 0.00 Array#+
0.00 7.80 0.00 6 0.00 0.00 Kernel.instance_of?
0.00 7.80 0.00 17 0.00 0.00 Fixnum#==
0.00 7.80 0.00 11 0.00 0.00 Enumerable.inject
0.00 7.80 0.00 22 0.00 0.00 Kernel.is_a?
0.00 7.80 0.00 24 0.00 0.00 Module#const_get
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.loadable_constants_for_path
0.00 7.80 0.00 4 0.00 52.50 Module#local_constant_names
0.00 7.80 0.00 2 0.00 0.00 Class#inheritable_attributes
0.00 7.80 0.00 2 0.00 0.00 Module#attr_accessor
0.00 7.80 0.00 1 0.00 0.00 WillPaginate::PerPage.per_page=
0.00 7.80 0.00 2 0.00 0.00 Hash#each
0.00 7.80 0.00 2 0.00 0.00 ActiveSupport::Dependencies.mechanism
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.load_once_path?
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.autoload_once_paths
0.00 7.80 0.00 1 0.00 320.00 Kernel.load
0.00 7.80 0.00 3 0.00 0.00 ActiveModel::EachValidator#check_validity!
0.00 7.80 0.00 28 0.00 0.00 Array#wrap
0.00 7.80 0.00 1 0.00 0.00 String#camelize
0.00 7.80 0.00 2 0.00 265.00 ActiveSupport::Dependencies.new_constants_in
0.00 7.80 0.00 2 0.00 0.00 Hash#include?
0.00 7.80 0.00 1 0.00 0.00 Array#collect
0.00 7.80 0.00 26 0.00 0.00 Array#last
0.00 7.80 0.00 3 0.00 0.00 ActiveSupport::Dependencies.to_constant_name
0.00 7.80 0.00 6 0.00 0.00 String#sub
0.00 7.80 0.00 2 0.00 0.00 Kernel.equal?
0.00 7.80 0.00 122 0.00 0.00 Hash#[]
0.00 7.80 0.00 3 0.00 0.00 Array#-
0.00 7.80 0.00 1 0.00 0.00 Module#remove_method
0.00 7.80 0.00 5 0.00 0.00 Hash#update
0.00 7.80 0.00 7 0.00 0.00 File#expand_path
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::DynamicFinderMatch#match
0.00 7.80 0.00 1 0.00 0.00 Kernel.singleton_class
0.00 7.80 0.00 6 0.00 0.00 ActiveSupport::Callbacks::Callback#matches?
0.00 7.80 0.00 5 0.00 8.00 ActiveSupport::Callbacks::ClassMethods.__define_runner
0.00 7.80 0.00 6 0.00 0.00 Module#method_defined?
0.00 7.80 0.00 5 0.00 0.00 Array#initialize_copy
0.00 7.80 0.00 10 0.00 0.00 ActiveSupport::Callbacks::Callback#_compile_options
0.00 7.80 0.00 2 0.00 0.00 Class#superclass
0.00 7.80 0.00 6 0.00 0.00 String#empty?
0.00 7.80 0.00 21 0.00 0.00 Array#join
0.00 7.80 0.00 2 0.00 0.00 ActiveSupport::Dependencies.load?
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::Base#_validators
0.00 7.80 0.00 1 0.00 0.00 Digest::Base#update
0.00 7.80 0.00 1 0.00 0.00 ActiveModel::Validations::ConfirmationValidator#setup
0.00 7.80 0.00 1 0.00 0.00 Integer#to_i
0.00 7.80 0.00 1 0.00 0.00 Class#inherited
0.00 7.80 0.00 5 0.00 0.00 ActiveSupport::Dependencies.log_call
0.00 7.80 0.00 1 0.00 0.00 Exception#backtrace
0.00 7.80 0.00 5 0.00 0.00 ActiveSupport::Dependencies.qualified_const_defined?
0.00 7.80 0.00 11 0.00 0.00 Array#first
0.00 7.80 0.00 6 0.00 0.00 ActiveSupport::Inflector.constantize
0.00 7.80 0.00 1 0.00 0.00 Digest::Class#digest
0.00 7.80 0.00 1 0.00 0.00 String#downcase!
0.00 7.80 0.00 1 0.00 0.00 Exception#initialize
0.00 7.80 0.00 24 0.00 0.00 Kernel.respond_to?
0.00 7.80 0.00 13 0.00 0.00 Module#const_defined?
0.00 7.80 0.00 52 0.00 0.00 Symbol#to_s
0.00 7.80 0.00 4 0.00 0.00 ActiveSupport::Dependencies.log
0.00 7.80 0.00 3 0.00 0.00 File#file?
0.00 7.80 0.00 1 0.00 410.00 ActiveSupport::Dependencies::ModuleConstMissing.const_missing
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.history
0.00 7.80 0.00 5 0.00 4.00 ActiveSupport::Callbacks::Callback#initialize
0.00 7.80 0.00 1 0.00 0.00 String#tr!
0.00 7.80 0.00 2 0.00 0.00 ActiveSupport::Dependencies::WatchStack#pop_modules
0.00 7.80 0.00 3 0.00 0.00 Regexp#===
0.00 7.80 0.00 24 0.00 0.00 Module#constants
0.00 7.80 0.00 15 0.00 0.00 Array#pop
0.00 7.80 0.00 11 0.00 0.00 String#split
0.00 7.80 0.00 1 0.00 7390.00 User#encrypted_password
0.00 7.80 0.00 3 0.00 0.00 ActiveRecord::Base#_destroy_callbacks
0.00 7.80 0.00 6 0.00 0.00 Object#duplicable?
0.00 7.80 0.00 1 0.00 0.00 String#underscore
0.00 7.80 0.00 1 0.00 0.00 Exception#exception
0.00 7.80 0.00 1 0.00 120.00 ActiveSupport::Dependencies::Loadable.require
0.00 7.80 0.00 1 0.00 0.00 Hash#reverse_merge
0.00 7.80 0.00 1 0.00 10.00 ActiveModel::Validations::HelperMethods.validates_presence_of
0.00 7.80 0.00 7 0.00 2.86 ActiveSupport::Callbacks::Callback#_compile_filter
0.00 7.80 0.00 9 0.00 0.00 ActiveRecord::Base#_validate_callbacks
0.00 7.80 0.00 10 0.00 0.00 Kernel.nil?
0.00 7.80 0.00 1 0.00 70.00 WillPaginate::PerPage::Inheritance.inherited
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::Base#_validators=
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::Base#respond_to?
0.00 7.80 0.00 1 0.00 0.00 Symbol#===
0.00 7.80 0.00 1 0.00 410.00 ActiveSupport::Dependencies.load_missing_constant
0.00 7.80 0.00 1 0.00 410.00 ActiveSupport::Dependencies.load_file
0.00 7.80 0.00 5 0.00 0.00 ActiveSupport::Callbacks::Callback#normalize_options!
0.00 7.80 0.00 34 0.00 0.00 Array#empty?
0.00 7.80 0.00 21 0.00 0.00 NilClass#nil?
0.00 7.80 0.00 2 0.00 0.00 Array#unshift
0.00 7.80 0.00 11 0.00 0.00 Hash#initialize_copy
0.00 7.80 0.00 1 0.00 0.00 String#scan
0.00 7.80 0.00 2 0.00 0.00 String#+
0.00 7.80 0.00 1 0.00 10.00 ActiveRecord::Base#after_destroy
0.00 7.80 0.00 4 0.00 0.00 Array#push
0.00 7.80 0.00 3 0.00 0.00 ActiveSupport::Callbacks::Callback#name
0.00 7.80 0.00 3 0.00 0.00 Kernel.freeze
0.00 7.80 0.00 8 0.00 0.00 Hash#delete
0.00 7.80 0.00 11 0.00 0.00 Array#extract_options!
0.00 7.80 0.00 40 0.00 0.00 Hash#[]=
0.00 7.80 0.00 4 0.00 0.00 ActiveSupport::Dependencies.constant_watch_stack
0.00 7.80 0.00 4 0.00 0.00 Module#ancestors
0.00 7.80 0.00 7 0.00 0.00 Kernel.hash
0.00 7.80 0.00 4 0.00 0.00 Object#presence
0.00 7.80 0.00 5 0.00 0.00 ActiveSupport::Callbacks::Callback#_compile_per_key_options
0.00 7.80 0.00 1 0.00 0.00 Kernel.instance_variable_set
0.00 7.80 0.00 4 0.00 0.00 Regexp#escape
0.00 7.80 0.00 3 0.00 0.00 Array#*
0.00 7.80 0.00 3 0.00 36.67 ActiveModel::Validations::ClassMethods.validates_with
0.00 7.80 0.00 5 0.00 0.00 Array#to_ary
0.00 7.80 0.00 1 0.00 0.00 String#initialize_copy
0.00 7.80 0.00 4 0.00 0.00 Array#flatten
0.00 7.80 0.00 1 0.00 80.00 ActiveModel::Validations::HelperMethods.validates_confirmation_of
0.00 7.80 0.00 5 0.00 26.00 ActiveSupport::Callbacks::ClassMethods.__update_callbacks
0.00 7.80 0.00 3 0.00 0.00 ActiveSupport::Callbacks::Callback#_normalize_legacy_filter
0.00 7.80 0.00 1 0.00 0.00 Kernel.require
0.00 7.80 0.00 25 0.00 0.00 Fixnum#+
0.00 7.80 0.00 8 0.00 2.50 Class#new
0.00 7.80 0.00 3 0.00 0.00 String#[]
0.00 7.80 0.00 3 0.00 0.00 String#gsub!
0.00 7.80 0.00 2 0.00 0.00 Array#uniq!
0.00 7.80 0.00 9 0.00 0.00 ActiveSupport::Dependencies.logger
0.00 7.80 0.00 11 0.00 0.00 ActiveSupport::Callbacks::Callback#start
0.00 7.80 0.00 32 0.00 0.00 Hash#default
0.00 7.80 0.00 3 0.00 0.00 File#join
0.00 7.80 0.00 3 0.00 0.00 ActiveModel::EachValidator#initialize
0.00 7.80 0.00 17 0.00 0.00 Kernel.send
0.00 7.80 0.00 28 0.00 0.00 Array#include?
0.00 7.80 0.00 5 0.00 0.00 NilClass#to_s
0.00 7.80 0.00 1 0.00 0.00 Array#shift
0.00 7.80 0.00 4 0.00 30.00 ActiveModel::Validations::ClassMethods.validate
0.00 7.80 0.00 5 0.00 0.00 Array#delete_if
0.00 7.80 0.00 3 0.00 0.00 Kernel.singleton_method_added
0.00 7.80 0.00 23 0.00 0.00 Object#method_added
0.00 7.80 0.00 1 0.00 70.00 ActiveModel::Observing::ClassMethods.inherited
0.00 7.80 0.00 1 0.00 0.00 ActiveModel::Observing::ClassMethods.notify_observers
0.00 7.80 0.00 2 0.00 50.00 ActiveSupport::Dependencies::WatchStack#new_constants
0.00 7.80 0.00 61 0.00 0.00 Array#<<
0.00 7.80 0.00 20 0.00 0.00 Kernel.object_id
0.00 7.80 0.00 2 0.00 0.00 Digest::Base#reset
0.00 7.80 0.00 1 0.00 20.00 ActiveRecord::Validations::ClassMethods.validates_uniqueness_of
0.00 7.80 0.00 5 0.00 26.00 ActiveSupport::Callbacks::ClassMethods.set_callback
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::Validations::UniquenessValidator#initialize
0.00 7.80 0.00 27 0.00 0.00 Array#[]
0.00 7.80 0.00 5 0.00 0.00 Module#name
0.00 7.80 0.00 1 0.00 0.00 String#size
0.00 7.80 0.00 1 0.00 120.00 ActiveSupport::Dependencies::Loadable.load_dependency
0.00 7.80 0.00 5 0.00 0.00 ActiveSupport::DescendantsTracker.descendants
0.00 7.80 0.00 4 0.00 0.00 Module#define_method
0.00 7.80 0.00 1 0.00 0.00 Enumerable.any?
0.00 7.80 0.00 1 0.00 0.00 NameError#initialize
0.00 7.80 0.00 7 0.00 0.00 String#==
0.00 7.80 0.00 503 0.00 0.00 Kernel.==
0.00 7.80 0.00 1 0.00 0.00 Object#initialize
0.00 7.80 0.00 17 0.00 0.00 Array#compact
0.00 7.80 0.00 6 0.00 0.00 Hash#extractable_options?
0.00 7.80 0.00 7 0.00 0.00 ActiveSupport::Dependencies.local_const_defined?
0.00 7.80 0.00 2 0.00 0.00 Set#<<
0.00 7.80 0.00 1 0.00 0.00 TrueClass#duplicable?
0.00 7.80 0.00 1 0.00 0.00 Array#reverse
0.00 7.80 0.00 1 0.00 0.00 ActiveRecord::Validations::UniquenessValidator#setup
0.00 7.80 0.00 23 0.00 0.00 ActiveRecord::Callbacks::ClassMethods.method_added
0.00 7.80 0.00 29 0.00 0.00 Module#===
0.00 7.80 0.00 4 0.00 27.50 Module#local_constants
0.00 7.80 0.00 3 0.00 0.00 User#_validators
0.00 7.80 0.00 4 0.00 0.00 Hash#merge
0.00 7.80 0.00 1 0.00 0.00 Module#remove_possible_method
0.00 7.80 0.00 4 0.00 0.00 Object#present?
0.00 7.80 0.00 2 0.00 0.00 String#gsub
0.00 7.80 0.00 1 0.00 0.00 Digest::Class#hexdigest
0.00 7.80 0.00 1 0.00 70.00 ActiveModel::Validations::ClassMethods.inherited
0.00 7.80 0.00 1 0.00 0.00 ActiveSupport::Dependencies.search_for_file
0.00 7.80 0.00 1 0.00 7800.00 #toplevel
edit app/models/user.rb