【轉】JMeter使用指南

來源:互聯網
上載者:User

標籤:

Abstract

  本文重點介紹JMeter工具在測試中地位以及其中一些難以理解或者手冊中含糊不清的感念,讀者可以通過本文瞭解這些概念,然後再根據自己的需要查閱JMeter中各個組件的具體用法來完成測試工作

  1. 簡介

  JMeter是一個專門用於測試C/S應用的案頭測試軟體(並不適合於B/S結構,因為它很難類比使用者在browser上的動作,如果需要測試B/S結構的應用,可以選擇Selenium這樣的工具),主要被用來完成功能測試壓力測試效能測試等工作。

  JMeter與其他測試軟體相比的優勢如下:

  • 它可以協助測試者很方便地類比出多使用者同時訪問伺服器的環境(通過Thread Group),這樣可以檢測出很多平時在單線程環境下無法暴露出來的問題。
  • 應用範圍很廣,幾乎所有你能想到的C/S應用它都能夠提供了相應的支。JMeter中自己定製了一些特定應用的測試方案,例如對HTTP Server的測試、對資料庫的測試、對Java程式的測試等。此外即使Jmeter沒有提供當前應用的測試環境,使用者也可以同昨BeanShell的方式自行定製。
  • 提供了豐富的邏輯控制器,可以允許測試人員很方便地寫出一些相對複雜的測試邏輯。
  • 提供完善的變數機制以及配置機制,協助測試人員減輕編寫用例的負擔,減少重複工作。
  • 提供了強大的監控組建,協助測試人員很方便地得到測試結果統計資訊。

  JMeter的劣勢:

  • 難以針對“正確性”進行測試。雖然JMeter提供了斷言機制,但是通常我們的測試在類比多使用者操作,因此某個使用者發出一個請求後得到的響應是不可預測的(例如同時對一個資料庫表進行讀寫,雖然我們可以讓每個類比使用者將寫入的資訊儲存在某個公用地區,但仍然可能會有問題,因為資料庫寫入的時間和寫入公用地區的時間並不能保證同步),因此如果想通過JMeter驗證應用的正確性還是比較麻煩的。通常我們只是利用斷言來檢查一些較為簡單而又重要的資訊,例如返回碼。
  • 沒有很好的BeanShell測試機制。在JMeter中,BeanShell是非常重要的一部分,因為通常JMeter定製的測試方案多少與我們的應用有些出入,這時就需要使用BeanShell來完成一些JMeter無法完成的工作。然而BeanShell也是需要保證正確性的,而JMeter並沒有對BeanShell的測試提供很好的支援。
  • 通過以上的分析,可以發現JMeter更適合找出被測試系統在並發環境下存在的問題。

  2. JMeter測試案例的基本結構

  JMeter測試案例的基本結構是一個類似於Windows資源管理員的樹形結構,這個樹中的每一個節點都由一個元素來表示,因此一個完整的JMeter測試案例實際上是由一個個元素組成的,而測試的執行過程實際上就是這些元素的執行過程。一般而言,JMeter會使用深度優先的方式遍曆這些元素,而對於同一層的元素,JMeter會自上至下地執行。

  在JMeter中有很多種元素,而每種元素在樹型結構中都有特定的意義,為了方便理解,這裡把這些元素從結構性質上分為三大類:

  第一類是控制型元素,這類元素通常出現在樹型結構的枝節點,它們被用來控制其下第一層元素(注意,不是其下所有元素)的執行,例如控制他們的先後順序,或者執行哪個或者不執行哪個。通過這類元素我們就可以很方便地動態控制測試案例的執行過程,這些元素就類似於變成語言中的if-else、switch、while等邏輯控制語句。

  第二類是動作型元素,這類元素是真正發起測試請求的元素,它們通常位於樹型結構的底層,每一個動作元素代表一次要求-回應的過程,他們的執行順序通常被控制型元素管理。

  第三類是配置型元素,它們只能作為樹型結構中的葉子節點,被用於對其作用範圍內(作用範圍的規則如下:如果該配置元素在控制元素下,則其作用範圍為該控制元素下的所有子孫節點;如果該配置元素在動作元素下,則其作用範圍僅為這一個動作元素)的所有動作型元素產生一定的影響。這些影響根據具體元素種類而不同,例如改變元素的參數、延遲請求時間、在請求前後加入一些動作、監聽請求及其相應。此外,如果某個動作型元素被多個相同的配置型元素影響後,這些配置型元素的效果就會進行Merge,Merge的規則依照元素的功能類型不同而不同(詳見第3節)。

  3. JMeter中的元素

  從功能上講,JMeter的元素分為八大類以及兩個特殊元素。這裡從使用場合上對這些元素進行敘述,至於具體每個元素什麼功能則需要查看JMeter的協助(具體方法是點擊未知的元素,然後選擇Help菜單下的Help選項)。

  • Test Plan元素:控制型元素。只能存在於樹型結構的根節點。它代表了整個測試方案,測試人員可以在這裡設定一些全域性的內容,例如全域變數(注意全域變數是Thread Local的,詳見第4節)、ClassPath配置(如果希望在Jmeter中調用自己的Java類就需要在這裡設定了)等。
  • Thread Group元素:控制型元素。只能存在於Test Plan元素之下。它代表了一組行為相似的使用者,通常我們把一類使用者的動作放在同一個Thread Group下,這樣就可以類比多這這樣的使用者了。在這裡可以配置類比使用者的個數(線程的個數)、迴圈次數、執行時間等。
  • Logic Controller:控制型元素。可以存在於Thread Group下任何位子。它用來完成控制其下元素的執行,JMeter提供了很多Logic Controller類型的元素,方便我們在測試中實現基本的邏輯。
  • Config Element: 配置型元素。這些元素被用來改變其作用範圍內所有動作元素的配置,利用該類元素可以減少很多測試案例編寫中的重複工作,例如可以讓一個HTTP Request Defaults元素來配置所有用例中HTTP請求的主機地址以及連接埠號碼,這樣就無須在每個動作元素中都做這樣的配置了。當Merge發生時,如果某個域只有一個Config Element元素有值,則使用該值;如果某個域有多個Config Element元素有值,則使用離動作元素最近的Config Element元素的值(在動作元素節點下的配置元素最近)。
  • Timer: 配置型元素。如果希望控制請求發出的頻率,則應該使用Timer延遲這些請求。當Merge發生時,所有Timer的時間會相加。
  • Pre Processor: 配置型元素。用於根據一定條件修改所有被影響的動作元素。當Merge發生時,這些Pre Processor將被依次執行,離動作元素最遠的先執行。
  • Post Processor: 同Pre Processor,只是發生在動作元素之後,用於從響應中提取需要的資訊。
  • Assertions: 配置型元素。用於對其影響範圍內的動作元素的結果進行斷言,例如可以斷言一些HTTP請求的返回碼,如果不通過則系統會記錄本次錯誤。Merge發生時,所有的Assertion都會被判斷。
  • Listener: 配置型元素。用於監聽其影響範圍內所有動作元素,測試結果資料主要由該類元素產生,因此他們非常有用。Merge發生時,所有的Listener監控動作都會被執行。
  • Sampler: 動作型元素。代表一次要求-回應的過程,他們是測試案例中動作的發起者,是測試案例的主要元素。JMeter根據不同的應用預製了很多種動作元素,如果使用者覺得仍然不夠用甚至可以用BeanShell Sampler寫自己的動作。

  4. JMeter中的變數

  有的時候我們希望發送成千上萬個隨機的請求,或者希望本次請求的內容依賴於前幾次的請求,那麼就需要使用JMeter中的變數(注意,是Variable不是Property),這樣就可以用變數來配置每一個請求,這樣就可以讓同一個Sampler每次都能發出不同的請求。

  使用變數時,首先必須注意的是,JMeter中的變數是線程獨立(Thread Local)的,也就是說雖然我們定義了n個變數,但是在每個線程中都有這n個變數的鏡像,他們之間相互獨立,互不干擾。

  當我們希使用變數的時候,首先需要建立所需的變數。在JMeter中建立變數的方式很多,一種途徑是通過Test Plan定義全域變數(用於所有的Thread Group,它也是線程獨立的),也可以通過Config Element中的User Defined Element來定義不同線程組的局部變數(注意,User Defined Element中定義的變數是用於整個線程組的,無論將這個元素放在哪裡都會被應用於整個線程組,這是一個比較特殊的配置型元素),此外當我們在應用中對某個沒有建立的變數賦值(後面會講到賦值)時也會建立該變數。實際上JMeter的源碼中是使用Map來實現變數的,因此這些性質也不難理解。

  當我們希望在某個地方引用一個變數的時候,可以通過${變數名}的文法來擷取變數的值。注意,如果這個變數沒有被定義,則這個式子就會被當作普通的字串。

  修改某個變數值的方法有很多,可以通過BeanShell來修改,也可以通過JMeter中一些特定的元素來修改(例如CSV Date Config Element),還可以使用JMeter函數來定義修改某個變數(具體如何做,見後面的小節)。

  通常情況下如果我們希望在每次迴圈中都發出不同的請求,那麼可以將可能的請求內容放在一個檔案中,並讓CSV Date Config Element從中擷取相應的值並交給變數,也可以通過BeanShell Sampler用指令碼來自己定製變數的值(注意不能使用Pre Processor中的BeanShell PreProcessor來定製變數,Pre Processor是用來修改請求中的域的,這個動作發生在請求被建立以後。也就是說如果我們在BeanShell PreProcessor中定義了一個變數,然後寫在請求域中,那麼結果就是JMeter先看到了一個沒有被賦值的變數,然後把這個${變數名}式子當作字串處理,然後再執行BeanShell PreProcessor。這一點是很多人容易犯錯誤的地方),也可以使用Pre Processor直接修改請求中的域,還可以在請求域中寫入一個JMeter函數,直接產生需要的值。

  在有些應用中,我們希望下一個請求的內容依賴於之前的請求。那麼我們就可以通過Post Processor將響應中的有用資訊抽取出來,然後賦值給一個變數,以便下次使用。

5. JMeter中的屬性

  在JMeter中有Property的概念,他們通常有兩種用處:首先他們代表了JMeter的配置資訊(存在JMeter目錄下的bin/jmeter.properties);其次他們可以被用來作為MemCache使用,以便線程間能夠通訊(Properties的get和put方法是安全執行緒的)。Property的擷取、定義、修改一般是通過JMeter函數來完成的,當然也可以通過強大的BeanShell。

  通常當我們希望多個線程之間有某種依賴關係時可以使用Property,但是這樣的需求並不多見,因為我們類比的使用者多半都是相互獨立的,他們並不應該知道其他人在幹什麼。

  此外我們還可以將一些常量配置在jmeter.properties檔案中,以便在測試中隨時使用

  6. JMeter中的函數

  有的時候我們需要執行一些簡單的操作(例如產生一個隨機數)而又不希望編寫BeanShell的Code,那麼可以考慮使用JMeter中內建的一些函數。這些函數的格式通常為${__函數名(參數1,參數2...)},他們有兩種方式來返回自己的執行結果:一種是直接返回,也就是說JMeter會在執行該函數後用函數的返回結果來替換原來調用函數的字串(例如假設${__method(1,2)}返回world,那麼如果我們在域中寫hello ${__method(1,2)},則實際的結果是hello world)。另一種是通過參數(通常是最後一個)指定一個變數後,JMeter會將執行結果存入該變數。具體使用哪種方式獲得結果是根據不同的函數而定的,JMeter提供了一個強大的函數產生器(Options菜單中的Function Helper Dialog選項),其中列出了所有的方法以及可能的函數,並且有方便的協助文檔,使用者可以通過該產生器來產生所需的函數。

  這裡有必要再次強調JMeter讀入一個域(任何一個可以填寫內容的空格)的過程:當JMeter讀入一個域中的字串後,會首先查看其中的是否存在能夠匹配${...}的字串,如果有則遞迴地解析這個${...}中的字串,直到括弧中的字串不再包含括弧為止。然後再解析這個${...}是否為一個函數或變數,如果是則用其結果覆蓋原來的${...}字串,直至將整個字串解析完畢。例如在輸入欄中輸入hello ${__method(${num},2)},而num變數的值為1,則這個字串首先被轉化為hello ${__method(1,2)},然後由於${__method(1,2)}的值為world,則最終這個域中的內容為hello world。

  掌握了以上內容後基本就可以將JMeter中的函數和變數運用自入了,而讀者所需做得事情只是查看手冊瞭解那些函數能夠提供何種功能。(注意有些函數是不能放入一些特殊的域中的,例如${__threadNum}就不能放在Test Plan的變數定義或者User Defined Element中的變數定義域中,具體原因手冊上講的很明白)

  7. JMeter中的BeanShell

  在多數情況下,JMeter提供的功能是不夠我們使用的,我們的測試案例中可能會存在一些比較複雜的邏輯,而這些邏輯又不發通過簡單的函數來實現,那麼我們就必須動用強大的BeanShell了(JMeter有一些元素專門用於在測試的不同地方加入BeanShell指令碼,如BeanShell Sampler)。不幸的是,JMeter的手冊中並沒有介紹BeanShell如何使用,而是把責任全部推給了BeanShell的網站,BeanShell的網站中的確有完整的BeanShell使用手冊,但是我們總不希望為了做測試又去學習一個指令碼語言,因此這裡給出了一些BeanShell的簡單應用,如果覺得不夠的話再去查看更加複雜的應用。

  7.1 BeanShell快速上手

  BeanShell是面向Java的指令碼語言,因此如果你想在完全不會BeanShell的前提下使用他,那麼直接編寫Java code就可以了。唯一需要注意的是,BeanShell支援若類型的變數,也就是不用指定變數類型,只要給他賦值就好了,BeanShell知道這個變數的類型。無論這個若類型變數在哪裡被使用,其後的代碼都能訪問這個變數,這與強型別俄變數不同。例如:

 

  view plaincopy to clipboardprint?

  // Arbitrary code block

  {

  y = 2;      // Untyped variable assigned

  int x = 1;  // Typed variable assigned

  }

  print( y ); // 2

  print( x ); // Error! x is undefined.

  // Arbitrary code block

  {

  y = 2;      // Untyped variable assigned

  int x = 1;  // Typed variable assigned

  }

  print( y ); // 2

  print( x ); // Error! x is undefined.

 

  7.2 JMeter內建變數

  JMeter在它的BeanShell中內建了變數,使用者可以通過這些變數與JMeter進行互動,其中主要的變數及其使用方法如下(JMeter文檔並沒有對該部分內容進行詳細講解,這裡也會說明他們分別對應於JavaDoc中的哪個類):

  • vars:這個變數實際引用了JMeter線程中的局部變數容器(本質上是Map),因此可以通過put和get方法訪問JMeter中的變數。這個變數是所有內建變數中最有用的,它是測試案例與BeanShell互動的橋樑。對應於org.apache.jmeter.threads.JMeterVariables
  • props:該變數引用了JMeter的配置資訊,它的使用方法與vars類似,但是只能put進去String類型的值,而不能是一個對象。對應於java.util.Properties。
  • ctx:該變數引用了當前線程的上下文,理論上通過這個東西我們幾乎可以控制當前線程相關的一切,不過這要求使用者非常熟悉JMeter的源碼。對應於org.apache.jmeter.threads.JMeterContext。

  7.3 在BeanShell中使用Java類

  有的時候我們希望發送數個請求,而這些請求的內容是通過一個Java類來實現的,這時就需要讓JMeter來調用這個Java類,而唯一的途徑就是通過BeanShell。

  為了能夠載入Java類,我們首先需要在Test Plan中添加自訂Java類所在的Class Path,然後就可以在BeanShell中import這個Java類,最後再將獲得的內容放入vars變數中,這樣就可以在其他地方通過${...}的方式擷取該變數的資訊了。

  例如,建立了一個com.linhao.A類在/root/Java檔案夾下,該類有一個方法hello()返回一個"Hello World"字串,那麼如果想在請求中使用這個方法返回的字串,則進行如下操作:

  首先在Test Plan下添加ClassPath為/root/Java

  然後在請求前添加一個BeanShell Sampler並寫入如下代碼:

 

  view plaincopy to clipboardprint?

  import com.linhao.A;

  vars.put("word", A.hello());

  import com.linhao.A;

  vars.put("word", A.hello());

 

  最後在需要使用該字串的地方寫${word},這樣最終這個域將被替換為Hello World

  7.4 JMeter下BeanShell的調試

  BeanShell也是代碼,應此也可能會有錯誤,而JMeter又是一個圖形介面的程式(也有命令列模式,但並不變於在設計用例階段使用),因此很多時候用例的設計者並不能確定BeanShell中某些變數是否正確。一個簡單的辦法是使用BeanShell建立一個對話方塊,然後將需要檢測的變數值顯示在對話方塊中。代碼如下:

 

  view plaincopy to clipboardprint?

  JFrame frame = new JFrame( a ); //a is a variable to be checked

  frame.setVisible(true);

  JFrame frame = new JFrame( a ); //a is a variable to be checked

  frame.setVisible(true);

 

  這樣當測試執行到這裡的時候就可以知道變數a的值了。

  雖然BeanShell很強大,但是它畢竟是一個指令碼語言,因此如果測試參數的產生邏輯很複雜,則還是應該把主要邏輯放在Java類中,然後讓BeanShell去調用,BeanShell只用來處理一些較為簡單的操作。

【轉】JMeter使用指南

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.