全方位解讀Ruby on Rails性能測試技巧
Ruby on Rails是一個非常實用WEB開發框架。不過它的性能到底如何呢?這需要我們進行詳細的測試。那么如何進行Ruby on Rails性能測試呢?#t#
Ruby on Rails性能測試1. 要進行Ruby on Rails性能測試,我們首先要模仿大量的數據,我們現在知道,在test/fixtures/目錄下的yml文件里添加我們的測試數據,在運行測試時,這些數據會被加載到數據庫。但是一條兩條數據還可以,數據多的情況下,一條一條在yml文件里寫可不行,所以,我們先看看怎樣在yml文件里造大量的數據。在fixtrue目錄下創建一個子目錄performance,在里面新建order.yml文件,把內容改成下面的樣子:
- # Read about fixtures at
http://ar.rubyonrails.org/
classes/Fixtures.html - <% for i in 1..100 %>
- order_<%= i %>:
- id: <%= i %>
- name: Fred
- email: fred@flintstones.com
- address: 123 Rockpile Circle
- pay_type: check
- <% end %>
然后再運行我們一個空測試,order_test.rb
depot>ruby test/unit/order_test.rb
到數據庫里查看下表order,里面已經初始化了100條記錄了。我們之所以要新建一個performance目錄,是因為我們不想運行每個測試都要初始化100條記錄,我們之前在測試model和controller的時候用的那個order.yml文件中的記錄就夠了。
Ruby on Rails性能測試2. 在test目錄下也創建一個performance目錄,然后創建一個order_test.rb文件,內容如下:
- require File.dirname(__FILE__)
+ '/../test_helper'- require 'store_controller'
- class OrderTest < Test::Unit::TestCase
- fixtures :products
- HOW_MANY = 100
- def setup
- @controller = StoreController.new
- @request = ActionController:
:TestRequest.new- @response = ActionController
::TestResponse.new- get :add_to_cart, :id => 1
- end
- def teardown
- Order.delete_all
- end
- def test_save_bulk_orders
- elapsedSeconds = Benchmark::realtime do
- Fixtures.create_fixtures
(File.dirname(__FILE__) +- "/../fixtures/performance", "orders")
- assert_equal(HOW_MANY, Order.find_all.size)
- 1.upto(HOW_MANY) do |id|
- order = Order.find(id)
- get :save_order, :order => order.attributes
- assert_redirected_to :action => 'index'
- assert_equal("Thank you for your
order.", flash[:notice])- end
- end
- assert elapsedSeconds < 3.0,
"Actually took #{elapsedSeconds} seconds"- end
- end
在這里,我們沒有直接加載100個order,而是在test_save_bulk_orders方法中,先使用elapsedSeconds = Benchmark::realtime來計算測試花費的時間,再通過調用create_fixtures方法指定我們要加載order的yml文件,然后對每條加載的order,進行保存,在通過斷言判斷是否調用了index的Action,和Flash中的內容。***再判斷elapsedSeconds是否小于3秒。
還有一點要注意,這里實際上對每個order進行了兩次Save操作,一次是在加載yml文件的時候,一次是我們調用save_order的時候。
Ruby on Rails性能測試3. 如果我們不想在每個測試運行的時候都從yml文件里加載數據,那么我們可以通過self.use_transactional_fixtures來控制。例如:
- class OrderTest
< Test::Unit::TestCase- fixtures :products
- self.use_transactional
_fixtures = true- HOW_MANY = 100
- ……
- end
Ruby on Rails性能測試4. 如果我們想知道某個方法或某句代碼所花費的時間,可以通過rails的腳本script/profiler and script/benchmarker來查看,例如,我們注意到Product這個Model的search方法比較慢,為了避免盲目地進行優化,我們使用Profiler來告訴我們每句代碼使用了多少時間,例如:
depot>ruby script/performance/profiler "Product.salable_items"
注意這里的script的路徑,我在instantrails里的和書上的不一致,如果提示腳本找不到,那就在自己的本地目錄找找看profiler文件放在什么地方。
Ruby on Rails性能測試5. 我們還可以使用benchmarker來比較兩個方法所消耗的時間,例如:
ruby script/performance/benchmarker 10 "Product.salable_items" "Order.count_pending"
輸出結果是:
user system totalreal
#1 0.078000 0.000000 0.078000 ( 0.078000)
#2 0.000000 0.000000 0.000000 ( 0.016000)
在這里,書上寫的是兩個方法之間用“”來分割,在我的機器上是使用一個空格來分割。