在哪裏設置實現最優腳本重用的屬性java
因爲支持雲的應用程序一般能夠輕鬆、快速地進行復制和部署,因此能夠在多種環境中對其進行測試。若是您須要在多個環境中測試和運行自動化腳本,那麼能夠在 JMeter 中使用一個獨立的屬性文件爲鏈接資源(如,應用服務器和數據庫)定義數據(包括登陸憑據),這樣作頗有好處。正則表達式
在 JMETER_HOME/bin 目錄下的三個文件中定義 JMeter 的屬性和變量。在啓動 JMeter 時,它會按如下順序加載這些文件:算法
當 JMeter 正在運行的時候,若是要添加任何新屬性或改變現有的屬性,則必須先關閉 JMeter,而後從新啓動它,使更改生效。數據庫
jmeter.properties 文件存儲與 JMeter 應用程序自己有關的屬性。這個文件中僅 保留了特定於 JMeter 程序的屬性或特定於框架的屬性。建立一個單獨的文件(文件名由您選擇),用該文件來存儲測試環境特定的屬性和變量,它們對於和接受測試的應用程序有關聯的全部腳原本說是全局的屬性和變量 — 例如,管理員的用戶名/密碼。在 jmeter.properties 文件中,取消對 user.properties 設置的註釋,並將 user.properties 的值設置爲所建立的文件的名稱。清單 1 中的示例將該值設置爲 myuser.properties:編程
清單 1. 在 jmeter.properties 文件中指定一個用戶屬性文件json
# Should JMeter automatically load additional JMeter properties? # File name to look for (comment to disable) user.properties=myuser.properties
清單 2 中的示例用戶屬性文件顯示了在用戶屬性文件中定義變量所用的格式。(在該定義中,等號左邊的任何地方都不容許有空格;必要時,屬性值能夠包含空格)。服務器
清單 2. 示例用戶屬性文件網絡
#---------------------------------------------------------------- # FVT API Test Environment parameters #---------------------------------------------------------------- # # --- Login Credentials USER_LOGIN=admin@in.ibm.com USER_PASSWORD=password # # --- Application Server APP_SERVER=localhost APP_PORT=80 APP_CONTEXT=ctx PROTOCOL=http # # --- Database Server${DB_NAME} DB_HOST=localhost DB_PORT=50000 DB_NAME=dbname DB_USER=dbadmin DB_PASSWORD=dbpassword
應保留 JMeter 的第三個屬性文件 system.properties,以便必須爲全部腳本定義的全系統屬性可以使用它。例如,若是您的全部腳本都使用某個特定的數據庫服務器,那麼您能夠在 system.propterties 文件中指定相關的屬性。架構
JMeter 的 User Defined Variables 控制面板(如圖 1 所示)顯示了 JMeter 腳本如何讀取在用戶屬性文件中定義的屬性。併發
圖 1. JMeter 腳本如何讀取在用戶屬性文件中定義的配置數據
控制面板的 Value 列中的每一個項目的格式爲:
${__property(VARIABLE_NAME,VARIABLE_NAME)}
例如,來自用戶屬性文件的 USER_LOGIN 變量被讀取爲腳本中的 ${__property(USER_LOGIN, USER_LOGIN)} 函數。括號中的第一個 USER_LOGIN 是在屬性文件中定義的變量的名稱(而且已在控制面板的 Name 列中列出)。若是屬性文件中沒有定義變量,那麼第二個實例是默認值或回退值。
什麼時候在屬性文件中定義一個變量,什麼時候將它定義爲 JMeter 腳本里面的一個變量,這些並無嚴格的規定。但有兩個準則能夠幫助您在多個 JMeter 腳本中實現一致性,並減小沒必要要的重複變量定義:
使用 JSON 模板文件實現有效負載分離
許多雲 API 要求使用 JSON 有效負載做爲輸入。JSON 定義了一組結構化的元素,能夠將它們嵌套在其餘元素中。每個元素定義一個或多個名稱/值對。功能測試包括以指定格式反覆提供數據。例如,在一個典型的 REST API 調用中,JSON 有效負載在 REST HTTP 請求的主體中傳遞,而且一般包含硬編碼的數據。硬編碼的數據一般會在多個測試中重複,並分散在整個腳本中。
這種方法的一個常見問題是,若是 JSON 結構(或數據)發現變化(也許是由於 API 參數的更改),那麼您必須進入 JMeter 測試,找到 HTTP 請求的主體,並修改 JSON 結構(和數據),以知足新的要求。若是在使用此 JSON 結構的多個 JMeter 測試用例中有數千個 HTTP 請求,那麼必須執行許多重複的編輯。
更好的方法是建立一個 JSON 結構模板,並定義數據目的地的替換字符串。JSON 模板不包含任何硬編碼的數據值,而是定義在腳本運行時隨實際數據一塊兒加載的引用變量。而後,模板被讀入 JMeter 腳本中的某個變量,並在 HTTP 請求主體中被替換。
清單 3 顯示了定義一個 JSON 有效負載的傳統方式:
清單 3. JMeter 測試計劃中的靜態 JSON 定義
{ "Customer":{ "CustomerType":"DIRECT", "CustomerNumber":"1234567890", "Organization":{ "OrgName":"IBM", "Phone":"999-999-9999", "AddressSet":[ { "AddressLine1":"Tech Park One", "AddressLine2":"", "AddressType":"MAILING", "City":"Pune", "Country":"India", "State":"Maharashtra", "StateCode":"MH", "PostalCode":"411006" } ], "Contact":{ "FamilyName":"Gilra", "GivenName":"Shalini", "EmailAddress":"shagilra@in.ibm.com", "NamePrefix":"Miss", "LanguagePreference":"EN_US", "WorkPhone":"999-9999" } } } }
清單 4 顯示了在模板中定義 JSON 的動態方式:
清單 4. 在外部 JSON 模板文件中的動態 JSON 定義
{ "Customer":{ "CustomerType":"${__eval(${STR_CUSTOMERTYPE})}", "CustomerNumber":"${__eval(${STR_CUSTOMERNUMBER})}", "Organization":{ "OrgName":"${__eval(${STR_ORGNAME})}", "Phone":"${__eval(${STR_PHONE})}", "AddressSet":[ { "AddressLine1":"${__eval(${STR_ADDRESSLINE1})}", "AddressLine2":"${__eval(${STR_ADDRESSLINE2})}", "AddressType":"${__eval(${STR_ADDRESSTYPE})}", "City":"${__eval(${STR_CITY})}", "Country":"${__eval(${STR_COUNTRY})}", "State":"${__eval(${STR_STATE})}", "StateCode":"${__eval(${STR_STATECODE})}", "PostalCode":"${__eval(${STR_POSTALCODE})}", } ], "Contact":{ "FamilyName":"${__eval(${STR_FAMILYNAME})}", "GivenName":"${__eval(${STR_GIVENNAME})}", "EmailAddress":"${__eval(${STR_EMAILADDRESS})}", "NamePrefix":"${__eval(${STR_NAMEPREFIX})}", "LanguagePreference":"${__eval(${STR_LANGUAGEPREFERENCE})}", "WorkPhone":"${__eval(${STR_WORKPHONE})}", } } } }
清單 3 中的 JSON 實體只包含硬編碼的數據。相反,清單 4 中的模板只包含引用變量的名稱,因此,任何 JMeter 測試計劃均可以使用模板。實際數據被單獨存儲在 CSV 數據文件中,咱們將在 下一節 討論它。
請注意,清單 4 中的 JSON 爲每一個已定義的替代變量調用了 JMeter __eval() 函數。增長的這一步驟使得在運行時執行 JMeter 腳本的時候能夠對變量進行計算。
圖 2 和圖 3 顯示瞭如何在 JMeter 測試腳本中指定 JSON 實體模板文件。圖 2 顯示了 HTTP Request 控制面板:
圖 2. 在測試中使用一個模板文件的內容
在圖 2 的示例中,CUSTOMER_JSON 變量表示整個JSON Customer 元素。該變量被封閉在 _eval() 函數中,顯示爲 HTTP 請求的主體(在 Parameters 選項卡上的 Send Parameters With the Request 標題下)。而後,在圖 2 中,請求主體是 ${_eval(${CUSTOMER_JSON})}。
在 User Parameters 控制面板中定義 CUSTOMER_JSON 變量,如圖 3 所示:
圖 3. 在 JMeter 腳本中讀取 JSON 模板文件
在圖 3 中,CUSTOMER_JSON 變量被設置爲 FileToString(),並使用指向 JSON 模板文件的路徑做爲參數。JSON 實體模板文件的全部內容都被讀入 CUSTOMER_JSON 變量。所以,JSON 實體模板文件的內容是在運行時計算的,所定義的全部替代字符串都被翻譯成爲它們定義的數據。(下一節 將說明替代變量如何與實際數據相關聯)。
由於 JMeter 的 JSON 實體模板文件對於 JMeter 測試腳本是外部文件,因此您能夠將它們存儲在一個單獨的目錄,好比 JMETER_HOME/tests/jsontemplates。當您訪問 JMeter 測試計劃中的某個 JSON 實體模板時,可指定相對於 JMeter BIN 目錄的名稱,例如:
../tests/jsontemplates/customer_template.json
您也能夠將模板存儲在 JMETER_HOME 目錄之外的地方,在這種狀況下,您必須提供絕對路徑。
使用 CSV Data Set Config 元素的數據抽象
雖然將測試數據與 JMeter 測試計劃分開在最初看起來像是執行了額外的工做,可是更簡潔的測試中的分離結果也更容易管理。在須要修改測試時,就能夠快速實現一些好處。某些數據可能仍然位於本地,存在於每一個測試計劃中,但大多數的測試數據抽象到外部文件中 — 在屬性文件(正如咱們前面討論過的)或一個 CSV 數據配置文件中。所產生的測試套件更易於維護,並且在大多數狀況下,不須要編輯 JMeter 測試計劃就能夠修改任何數據值。
JMeter 使用 CSV 文件存儲以逗號分隔的數據行。JMeter 框架的 CSV Data Set Config 功能提供了一種在運行時動態讀取 CSV 文件測試數據的方法。將測試數據存儲爲 CSV 另一個好處是,您能夠存儲多行表明多個數據對象/變量的數據,或循環處理的屢次迭代的數據。JMeter 2.3.4 及更高版本還支持提供一個 CSV 標題 做爲文件的第一行。而後,使用標題的分隔字符串名稱存儲所定義的數據值。一般狀況下,隨後每一行的數據都表明循環的一次迭代。從這個意義上講,該腳本主要是 「數據驅動的」,測試人員能夠修改 CSV 文件中的數據,無需對 JMX 腳本進行任何更改。
測試人員還能夠跨多個測試線程共享數據,並在多個 CSV 文件中存儲測試數據。例如,若是有一個測試用一組用戶憑據登陸,而後爲該用戶建立一個訂單,那麼您能夠建立兩個 CSV 文件:一個用於保存用戶憑據,另外一個用於保存訂單信息。有時候,可能須要建立多個 JMX 腳原本訪問 CSV 文件。在這種狀況下,您必須將 CSV 文件放在多個腳本均可以訪問的位置。
在一個 CSV 文件內定義的迭代數據一般與變量名稱有關聯。您能夠在標題中定義這些變量名稱,用逗號分隔,而且它們一對一地與數據值的數量相匹配。當 JMeter 處理文件的每一行時,它會將適當的數據值分配給與該位置有關聯的變量名稱。清單 5 顯示了樣例 CSV 文件的內容:
清單 5. 樣例 CSV 文件 (customer.csv)
"STR_TESTCASE","STR_CUSTOMERTYPE","STR_CUSTOMERNUMBER","STR_ORGNAME","STR_PHONE", "STR_ADDRESSLINE1","STR_ADDRESSLINE2","STR_ADDRESSTYPE","STR_CITY","STR_COUNTRY", "STR_STATE","STR_STATECODE","STR_POSTALCODE","STR_FAMILYNAME","STR_GIVENNAME", "STR_EMAILADDRESS","STR_NAMEPREFIX","STR_LANGUAGEPREFERENCE","STR_WORKPHONE", "Testcase1","DIRECT","1234567890","IBM","999-999-9999","Tech Park One","","MAILING", "Pune","India","Maharashtra","MH","411006","Gilra","Shalini","shagilra@in.ibm.com","Miss", "EN_US","999-9999", "Testcase2","DIRECT","1234567891","IBM","999-999-9999","Tech Park One","","MAILING", "Pune","India","Maharashtra","MH","411006","Prakash","Prem","premprakash@in.ibm.com", "Mr","EN_US","999-9999", "Testcase3","DIRECT","1234567892","IBM","999-999-9999","550, Kings Street","","MAILING", "Littleton","United States","MA","MA","1460-1250","Tuohy","Tom","tuohy@us.ibm.com","Mr", "EN_US","999-9999",
在 JMeter 處理 清單 5 中的 CSV 文件時,對於第一次迭代,會將 Pune 分配給 STR_CITY 變量,將 India 分配給 STR_COUNTRY 變量,等等。而後,對接下來的兩行/迭代執行一樣的操做,但使用了在那些行上指定的值。當腳本運行的時候,所指定的變量加載幷包含它們的值,直到它們被覆蓋或腳本結束。爲了不無心中覆蓋了變量,請當心地命名變量。此外,當您調試 JMeter 腳本時,知道變量的起源在哪裏很是重要,由於腳本自己沒有定義該位置。在 CSV 文件中使用一致的變量名稱命名慣例頗有幫助。
圖 4 顯示瞭如何在 CSV Data Set Config 控制面板中指定 CSV 文件:
圖 4. 在 JMeter 中指定和讀取一個 CSV 文件
在圖 4 中,Filename 字段被設置爲將被讀取的 CSV 文件的相對路徑。「Allow quoted data?」 值被設置爲 true,由於 CSV 文件中的數據值用引號括了起來。「Recycle on EOF?」 選項被設置爲 false,「Stop thread on EOF?」 選項被設置爲 true,這將致使線程在到達文件結束(EOF)時中止。
使用 While Controllers 實現循環
在將測試數據分離成單獨的 CSV Data Set Config 文件後,能夠更容易地使用數據集在一組類似但獨立的操做中進行迭代。JMeter 提供了 While Controller 等循環構造函數來幫助實現迭代。經過在循環構造函數中組織測試操做,您能夠在一個 JMeter 測試計劃中執行所需的所有數據驅動的測試。
這種方法對於雲測試頗有用,由於它解決了測試從多個訪問角色或不一樣數據集(正、負、邊界值,等等)訪問 API 的需求。利用循環,能夠將一個 API 測試目標的全部測試排列都放在一個測試計劃中,這使得編寫測試用例的速度至少快了 20 倍。
圖 5 顯示瞭如何使用 While Controller 控制面板來告訴 JMeter 循環遍歷全部 CSV 文件數據:
圖 5. 循環遍歷 CSV 文件中的全部數據
在圖 5 中,Condition(函數或變量)字段被設置爲 jexl() 函數。此函數比較了來自 CSV 數據文件的變量與 EOF,當 CSV 文件中沒有其餘數據行時,它會告訴 JMeter 退出循環。條件能夠是最終計算結果爲 false 的任何變量或函數。
使用 BeanShell 編寫腳本
經過使用 BeanShell 腳本語言,您能夠在 JMeter 腳本中進行 Java 編程。例如,在腳本必須操縱用 JMeter 的 Regular Expression Extractor 捕獲的變量的狀況下,BeanShell 腳本頗有用。BeanShell 腳本執行傳遞給它的程序,並在運行時返回結果。
在某些雲應用程序中,使用了從 API 命令返回的響應數據(多是 JSON 格式的)做爲對另外一個 API 命令的請求數據,其中進行了一些修改。使用未知的動態數據可能很是棘手和困難,除非您能夠在腳本中使用編程。利用 BeanShell 腳本,經過使用 JSONObject 類庫,您能夠在運行時操縱 JSON 有效負載或讀取 JSON 有效負載的屬性值。爲了在 JMeter 腳本中使用 JSONObject,經過將 JAR 複製到 JMETER_HOME/lib 文件夾,能夠在 JMeter 的類路徑中包含 java json.jar。
您能夠針對不一樣目的,經過多種方式定義和使用 BeanShell 腳本。利用 BeanShell PreProcessor 或 PostProcessor,能夠在採樣器執行以前或以後應用 JMeter BeanShell Sampler 中的一段代碼。利用 BeanShell Assertion,能夠進行條件測試,好比 JMeter 變量是否保存了一個預期值。
定義並使用 BeanShell 腳本的通常步驟是:
清單 6 中的樣例 BeanShell 腳本修改了嵌套在 清單 3 中的 JSON 的第三層的 GivenName 和 WorkPhone 值:
清單 6. 使用 BeanShell 腳本修改兩個 JSON 值
custPayload= vars.get("testResp"); org.json.JSONObject custJSON= new org.json.JSONObject(custPayload); if (custJSON.has("Customer") && custJSON.get("Customer")!= null) { org.json.JSONObject contactJSON = custJSON.getJSONObject("Customer").getJSONObject( "Organization").getJSONObject("Contact"); contactJSON.put("GivenName", "Shalini"); contactJSON.put("MobilePhone", "9923406159"); } vars.put("updatedCustPayload", custJSON.toString());
如今,請求能夠在 API UPDATE 命令中使用 ${updatedCustPayload} 變量。
能夠經過其餘許多方式使用 BeanShell 腳原本操縱 JMeter 變量或 JSON 數據 — 好比執行算術運算、提取變量的值,或以一個特定變量的值替換另外一個變量的值。整體而言,BeanShell 可用於執行 JMeter 不直接支持的任務。
使用 Module Controller 模塊化可重用的片斷
一 個複雜的測試計劃中包括許多變量和函數,這很常見。一般狀況下,這些片斷在其餘測試計劃中也被使用超過一次或兩次。在這種狀況下,能夠將這些片斷拆分爲可 以在其餘地方重用的若干個子模塊,以便減小維護工做量。而後,若是一個可重用的功能在將來須要進行修改,您只須要在某個地方修改它。
JMeter Module Controller 是一種機制,能夠在運行時在目前的測試計劃中替換測試計劃片斷。片斷能夠位於任何線程組或在 WorkBench 上。Module Controller 使用的任何片斷都必須具備唯一的名稱,由於該名稱被用於在從新加載一個測試計劃時找到目標控制器。
圖 6 的示例顯示了放置 Module Controller 的位置,以及在腳本中調用的模塊:
圖 6. Module Controller 的放置和它指向的模塊
在圖 6 所示的測試計劃中,Register Customer 被定義爲一個單獨的模塊,被放置在 WorkBench 部分中。Module Controller (Module Controller - Register Customer) 被放置在 Login User 例程的後面和 Logout 的前面,指向 Register Customer 模塊。在運行腳本時,在 Module Controller 的所在位置上,Module Controller 替代了測試計劃中的 Register Customer 模塊。
圖 7 顯示瞭如何在腳本中定義一個 Module Controller:
圖 7. Module Controller 指向在 WorkBench 中定義的簡單控制器
在圖 7 中,從 Module To Run 字段的下拉列表選中 Register Customer 模塊,該列表列出了全部可用模塊。
當可重用的組件在同一個腳本(JMX 文件)中被重用時,可使用 Module Controller。若是在其餘腳本中也將使用可重用的片斷,那麼能夠將片斷移到一個單獨的 JMX 文件中,並使用 Include Controller 調用它,在下一節中將會詳細敘述該操做。
使用 Include Controller 包括可重用的 JMeter 文件
JMeter 的 Include Controller 提供了一個佔位符,其中一個 JMX 文件(父 腳本)能夠調用另外一個 JMeter 腳本(子 腳本)。經過將腳本拆分爲較小的腳本或模塊/例程,並使用這些子例程構創建一個測試套件,能夠在腳本中實現模塊化,以加強可理解性和可重用性。使用 Include Controller 分離可重用的代碼片斷或先決條件(如 Login User 和 Register User),幫助更好地管理和維護腳本。
要使用 Include Controller,首先須要建立一個子 JMX 文件,其中包含一個可重用的例程(如 Login Admin User)。圖 8 顯示了一個示例子腳本,經過 Include Controller 能夠將它包含在父腳本中:
圖 8. 子 JMX 文件 (LoginUser.jmx)
圖 8 中的子腳本定義了一個測試計劃,其中包含一個採樣程序和一個 Login User 的 HTTP 請求。在 HTTP 請求中,協議、服務器名稱和其餘設置所使用的變量是在父腳本中定義的。
下一步是在父腳本中想要調用子腳本的地方添加一個 Include Controller,並將 Include Controller 指向子 JMX 文件的路徑。圖 9 顯示了一個在父腳本中定義的 Include Controller:
圖 9. 在父 JMX 文件中添加一個 Include Controller
在圖 9 所示的 Include Controller 控制面板中,Filename 字段存儲了子 JMX 文件(在本例中是 Login_User.jmx)的相對路徑。
子 JMX 文件能夠訪問在 Include Controller 中能夠訪問的父 JMX 文件中定義的任何變量,而且父 JMX 文件可使用在子 JMX 文件中定義的變量。
使用正則表達式
當 JSON 是 REST 操做的請求負載時,響應要麼是 JSON 格式的,要麼是字符串表示形式。在完成操做後,必須提取響應字符串、錯誤代碼和錯誤消息字符串,以驗證特性是否如預期般運做。您可使用 JMeter 的正則表達式特性來提取變量中的響應數據。
圖 10 顯示瞭如何在 JMeter 的 Regular Expression Extractor 控制面板中建立一個簡單的正則表達式提取器:
圖 10. 簡單的正則表達式提取器
在圖 10 中,Reference Name (在本例中是 User)存儲使用正則表達式語法提取的值。在 Regular Expression 字段中,您爲針對響應運行的正則表達式提供了語法(在 圖 11 中,該語法是 \"LoginName\":\"(.*?)\"),以提取特定數據。JSON 響應數據的經常使用正則表達式語法示例包括:
在 圖 10 的 Template 字段中,$1$ 表示參考變量的分組。Default Value 字段用於在正則表達式不匹配的狀況下爲調試提供默認值。根據實踐,只有在腳本階段添加和測試正則表達式模式的時候才聲明默認值。
擴展功能 JMeter 腳本以執行性能測試
理想狀況下,任何應用程序的性能測試都包括兩個場景:用戶數量尖峯和系統負載的增長。若是現有的功能測試場景涵蓋了基本的 REST 函數,那麼很容易擴展和更新它,從而測試託管在雲基礎架構上的 REST 服務的性能。您能夠修改應該被髮送到每一個服務器的請求的數量,對應用程序進行加載測試。您能夠經過配置使用適當循環迭代的上升期 來控制請求的數量。
例如,假設您有一個測試計劃,基於如下算法執行和驗證一組簡單的 REST 原則:
您能夠將簡單的功能測試計劃(最初爲 RESTful API 功能測試場景而設計)調整爲一個以雲環境中部署的服務器爲目標的性能測試腳本。
圖 11. 圖 11. 性能仿真設置示例
圖 12. 性能測試模擬變量
在圖 12 中,Loop 值被設置爲 5,RampUp 值被設置爲 50,Loop 值被設置爲 2。
圖 13 顯示了基於圖 12 中已配置的變量值,對在雲應用程序中部署的其中一個節點服務器執行 JMeter 的結果:
圖 13. 性能測試結果
圖 13 顯示了發送到服務器的併發請求的沉重負載,以模擬性能測試條件。
擴展功能 JMeter 腳本,以執行可靠性測試
可靠性測試 是經過在多組特定條件下連續運行一組腳本,確保總體系統穩定性的一種方式。可靠性測試的結果應該與壓力測試、功能測試和網絡特性測試的結果一塊兒查看。
與性能測試同樣,您能夠將執行和驗證一組簡單的 REST 原則的測試計劃轉換爲一組合適的可靠性測試腳本,以肯定雲實例上運行的任何產品或特性的穩定性。
可靠性測試的一個重要方面是,肯定在連續多日運行一個腳本的過程當中是否發生故障。選中 Thread Group 控制面板的 Forever 複選框,如圖 14 所示,讓線程能夠一直運行,直到測試失敗或腳本被強行中止:
圖 14. JMeter 腳本的可靠性設置
在配置了可靠性測試設置後,運行測試幾天,經過 JMeter 結果圖或經過 JMeter 提供的推斷選項連續監測結果。
結束語
本文向您介紹了使用 JMeter 來有效地測試基於雲的應用程序的方法。文章並無進行詳盡的討論,咱們鼓勵您嘗試使用其餘技術來改進 JMeter 中的自動化任務實現。JMeter Wiki是繼續您的探索的一個好地方。