qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          LoadRunner 性能測試腳本

            1   概述

            腳本錄制編寫是性能測試的一個重要環(huán)節(jié)。在性能測試過程中,虛擬用戶模擬真實用戶使用被測系統(tǒng),這個“模擬”的過程正是通過性能測試腳本來實現(xiàn)的。因此,編寫一個準確無誤的腳本對性能測試有至關(guān)重要的意義。完成性能測試腳本包括兩個步驟:腳本錄制和腳本編寫,本文重點關(guān)注腳本編寫。

            2   腳本錄制

            2.1.錄制方式

            HTTP協(xié)議腳本錄制可選兩種方式:基于HTML和基于URL。選擇哪種錄制方式的原則如下:基于瀏覽器的HTTP應用系統(tǒng)選擇HTML,基于其他方式的HTTP應用系統(tǒng)選擇URL。

            2.2.錄制注意點

            取消錄制期間自動關(guān)聯(lián)功能;

            如果部分測試腳本出現(xiàn)問題,需要重新錄制,可以只錄制存在問題的片斷腳本,方法是不選中錄制啟動對話框中的Record the application startup。

            3   腳本編寫

            3.1.常用技術(shù)

            LoadRunner性能測試腳本編寫常用的技術(shù)包括參數(shù)化,關(guān)聯(lián),邏輯控制和腳本模塊化。

            3.1.1.參數(shù)化

            參數(shù)化就是將腳本中的常量轉(zhuǎn)化為變量的過程。通過錄制生成的腳本所有的數(shù)據(jù)都是常量,為了達到向服務器發(fā)送的數(shù)據(jù)多樣化的目的,需要將一些數(shù)據(jù)常量轉(zhuǎn)化為變量。

            3.1.2.關(guān)聯(lián)

            關(guān)聯(lián)就是查找動態(tài)數(shù)據(jù),并把查詢到的數(shù)據(jù)以參數(shù)的形式保存起來。在B/S或者C/S系統(tǒng)中,服務器返回給客戶端的數(shù)據(jù)有些是動態(tài)改變的,例如客服系統(tǒng)的人工來話流水號和工作流系統(tǒng)的工單流水號。當打開工單生成頁面后,工單流水號已經(jīng)從服務器端獲取到了,而在提交工單步驟,需要將該流水號返回給服務器。因此,在提交工單之前,在腳本中必須獲得流水號。獲得流水號的方法就是關(guān)聯(lián)。

            使用關(guān)聯(lián)功能動態(tài)保存的參數(shù)跟直接通過參數(shù)化生成的參數(shù)是一致的。唯一不同的是,通過參數(shù)化生成的參數(shù)在腳本中可以高亮顯示。

            3.1.3.邏輯控制

            業(yè)務系統(tǒng)在實際應用中,業(yè)務操作步驟間往往存在邏輯。比如,客服3.0工作流系統(tǒng),業(yè)務代表處理工單,如果待辦區(qū)沒有工單等待處理,則先從工單池中提取工單到待辦區(qū),然后進行處理,并且需要優(yōu)先處理超時或即將超時的工單。在工單處理的性能測試腳本中,也必須遵從這種業(yè)務邏輯。

            LoadRunner性能測試腳本采用C語言,因此腳本邏輯控制同C語言一致,使用if,switch,while/for/do控制結(jié)構(gòu)。

            3.1.4.腳本模塊化

            腳本模塊化的目的是:提高腳本可讀性、可重用性和腳本生產(chǎn)效率。腳本模塊化的本質(zhì)是抽取函數(shù),一些很通用的函數(shù)甚至可以封裝為DLL。模塊化性能測試腳本的思想跟自動化測試的ActionWord有相似之處。

            例如:客服3.0系統(tǒng)的登錄功能,無論是工作流、知識庫、公告便簽還是培訓考試,它們都使用相同的登錄頁面。我們可以把登錄腳本抽取為一個函數(shù)csp_login(char *staffno,char * password),需要登錄操作時,不需要錄制和拷貝腳本,只要調(diào)用這個函數(shù)就可以了。

            注意:并不是所有的腳本代碼塊都需要做模塊化處理,只有那些穩(wěn)定不變、并且經(jīng)常用到的代碼塊才需要做模塊化處理。不做得不償失的事。

            3.2.典型函數(shù)

            LoadRunner中,常用的函數(shù)有很多,這里只介紹編寫性能測試腳本過程中那些必然用到的函數(shù)。本文重點關(guān)注這些典型函數(shù)的應用場合及注意點,至于函數(shù)詳細使用說明請參見LoadRunner幫助文檔。

            3.2.1.事務相關(guān)

            3.2.1.1. lr_start_transaction/lr_end_transaction

            功能:事務開始/結(jié)束標記。

            應用場合:需要統(tǒng)計某一段代碼塊執(zhí)行所需要的時間,這兩個函數(shù)需要成對使用。

            舉例:工作流系統(tǒng)性能測試中有一個需求,300人在線,提交工單操作平均響應時間在3秒以內(nèi),則需要在提交工單請求步驟之前插入lr_start_transaction,提交工單請求步驟之后插入lr_end_transaction。

            注意點:這兩個函數(shù)只是標記函數(shù),用于標記事務開始/結(jié)束,因此可以嵌套使用,即事務中還可以包含子事務。

            3.2.1.2. lr_think_time

            功能:模擬思考時間,即等待時間。

            應用場合:在線用戶測試,為了讓每一個虛擬用戶模擬一個真實用戶的行為,即讓一個虛擬用戶對系統(tǒng)產(chǎn)生的壓力跟真實用戶相當,就必須使用這個函數(shù)。這是因為,用戶在使用系統(tǒng)的過程中,從一個操作轉(zhuǎn)換到另一個操作,是需要時間的,這個時間就是思考時間。

            舉例:客服3.0工作流系統(tǒng)在線用戶測試。對于工單查詢操作,輸入查詢條件后提交查詢,從輸入查詢條件至提交查詢的時間間隔就是思考時間。因為LoadRunner無法模擬鍵盤輸入的過程,它只能模擬鍵盤輸入的等待時間,此時需要在提交查詢的那個動作前插入lr_think_time函數(shù)。

            注意點:在錄制腳本中,原子事務內(nèi)不要包含lr_think_time函數(shù),否則該思考時間將被統(tǒng)計到事務響應時間中,造成結(jié)果不準確。另外lr_think_time是否啟作用,可通過runtime-seting進行設(shè)置。

            注:原子事務指那些不能再分割為更小事務的事務,它經(jīng)常指一個單一的業(yè)務操作,通常表現(xiàn)為一個URL請求。


           3.2.1.3. lr_rendezvous

            功能:在Vuser腳本中設(shè)置集合點。

            應用場合:并發(fā)測試。

            舉例:客服3.0培訓考試系統(tǒng),100人同時打開同一份試卷。則需要在打開試卷的語句前插入lr_rendezvous函數(shù),并在場景中設(shè)置集合點策略。

            注意點:非并發(fā)測試,例如在測試系統(tǒng)的處理能力時,最好不要設(shè)置集合點,因為一旦設(shè)置了集合點,將導致一些VUser處于等待狀態(tài),在這等待過程中服務器將是空閑的,這將導致不能準確的測試出服務器的真實性能水平。集合點更多用于發(fā)現(xiàn)系統(tǒng)的并發(fā)問題。

            3.2.2.參數(shù)化/關(guān)聯(lián)

            3.2.2.1.lr_save_string/lr_save_int

            功能:將某一字符串/整型保存為參數(shù)。

            應用場合:有些變量的值通過C語言生成,之后在測試腳本中要使用這些變量。

            舉例:客服3.0業(yè)務配置臺系統(tǒng)增加業(yè)務代表操作,業(yè)務代表的工號和姓名使用C語言函數(shù)生成。工號和姓名分別保存在staff_no和staff_name變量中,則在腳本中可以使用lr_save_int(staff_no,"staffno"),lr_save_string(staff_name, "stafffname")將工號和姓名參數(shù)化。

            注意點:無。

            3.2.2.2.web_reg_save_param

            功能:在服務器返回的文本中查找一個或者多個字符串,并將搜索到的字符串值保存在參數(shù)中。

            應用場合:在B/S或者C/S系統(tǒng)中,服務器返回給客戶端的數(shù)據(jù)有些是動態(tài)改變的,在腳本的下一個步驟中,需要使用該動態(tài)數(shù)據(jù)。這時,就需要使用關(guān)聯(lián)獲得該動態(tài)數(shù)據(jù)。

            舉例:客服3.0工作流系統(tǒng),工單辦理每次都從待辦區(qū)中打開第一條工單,為打開第一條工單,需要獲取第一條工單的完整URL(包括URL中的parameter及其值),而每一次進入待辦區(qū),第一條工單有可能是不一樣的。為獲取第一條工單的URL,將打開工單的URL做關(guān)聯(lián)。已知打開待辦區(qū)操作獲得的HTML有如下片斷:

            <a href="#"onclick="javascript:openseviceforprocess('/iwflow/FindJspID.jsp?serialNo=2008092200000033&serviceID=0099&nodeID=140004&dealID=2008092200000056&hisFlag=0&skillID=020401&dealSkillID=020101&dealStaff=1200','false');">

            可在打開待辦區(qū)的操作前插入如下語句:

            web_reg_save_param("tt_url", "LB=javascript:openseviceforprocess('","RB=','false')", "Ord=1","IgnoreRedirections=Yes", "Search=Body","RelFrameId=1", LAST );

            運行腳本后,tt_url的值為:

            /iwflow/FindJspID.jsp?serialNo=2008092200000033&serviceID=0099&nodeID=140004&dealID=2008092200000056&hisFlag=0&skillID=020401&dealSkillID=020101&dealStaff=1200

            這個URL就是打開第一條工單的URL,有了URL,便可打開工單。

            注意點:

            (1)LoadRunner工具只能識別文本,在HTTP協(xié)議中只能識別HTML文檔,因此關(guān)聯(lián)的依據(jù)是HTML源碼,而不是經(jīng)過瀏覽器解析后的可視化文本。這一點很重要。

            (2)關(guān)聯(lián)還能將多個匹配的參數(shù)保存在數(shù)組中,方法是指定ORD的屬性值為ALL,之后通過“{參數(shù)名_1}”, “{參數(shù)名_2}”, “{參數(shù)名_3}”格式可獲得數(shù)組元素的值。

            (3)該函數(shù)有一個屬性NOTFOUND,默認值為ERROR,也就是說,如果找不到要查找的數(shù)據(jù),將報出錯誤,在必要的時候,例如腳本邏輯控制需要,可以將NOTFOUND的屬性值設(shè)為WARNING,這樣LoadRunner將不產(chǎn)生錯誤。

            3.2.2.3.lr_save_searched_string

            功能:在某一個字符緩沖區(qū)中搜索指定的字符串,并將搜到的字符串保存在參數(shù)中。

            應用場合:可配合LoadRunner的關(guān)聯(lián)功能,靈活獲取服務器端返回的數(shù)據(jù)。

            舉例:客服3.0工作流系統(tǒng),工單處理每次都從待辦區(qū)中打開第一條工單,打開工單的URL已經(jīng)通過關(guān)聯(lián)保存在tt_url參數(shù)中,在工單處理提交時,需要使用serviceNo,serviceID,nodeID,dealID,tt_url的值如下:

            /iwflow/FindJspID.jsp?serialNo=2008092200000033&serviceID=0099&nodeID=140004&dealID=2008092200000056&hisFlag=0&skillID=020401&dealSkillID=020101&dealStaff=1200

            可使用以下函數(shù)保存serviceNo,serviceID,nodeID,dealID的值。

          //保存serialNo,serviceID,nodeID,dealID參數(shù)
          int getTTData(){
          int i = 0;int j=0;
          char *tt_url = lr_eval_string("{tt_url}");
          int len= strlen(tt_url);
          while(tt_url[i]!='='){i++;} while(tt_url[j]!='&'){j++;}
          lr_save_searched_string(tt_url,len,0,"serialNo",1,j-i-1,"serialNo");
          i++;j++;while(tt_url[i]!='='){i++;} while(tt_url[j]!='&'){j++;}
          lr_save_searched_string(tt_url,len,0,"serviceID",1,j-i-1,"serviceID");
          i++;j++;while(tt_url[i]!='='){i++;}  while(tt_url[j]!='&'){j++;}
          lr_save_searched_string(tt_url,len,0,"nodeID",1,j-i-1,"nodeID");
          i++;j++; while(tt_url[i]!='='){i++;}  while(tt_url[j]!='&'){j++;}
          lr_save_searched_string(tt_url,len,0,"dealID",1,j-i-1,"dealID");
          return 0;
          }

            注意點:無

            3.2.2.4.lr_save_datetime

            功能:將時間保存為參數(shù)。

            應用場合:應用系統(tǒng)需要把時間數(shù)據(jù)提交給服務器端。

            舉例:客服3.0工作流系統(tǒng)活動工單查詢,默認查詢從當天開始的最近三天工單。 則查詢的開始時間和結(jié)束時間可用lr_save_datetime獲取。

            lr_save_datetime("%y-%m-%d00:00", DATE_NOW-2*ONE_DAY, "queryBeginTime");

            lr_save_datetime("%y-%m-%d23:59", DATE_NOW, "queryEndTime");

            注意點:無

           3.2.2.5. web_save_timestamp_param

            功能:將當前時間戳保存為參數(shù)。

            應用場合:應用系統(tǒng)需要把時間戳提交給服務器端。

            舉例:多媒體坐席客戶端,在向MClient提交信息時,需要附帶客戶端的時間戳,則可以使用該函數(shù)獲取當前時間戳。

            注意點:與lr_save_datetime不同的是,本函數(shù)保存的是時間戳,而lr_save_datetime保存的是日期和時間。

            3.2.2.6.lr_eval_string

            功能:將某一字符串中包含的所有參數(shù)替換為真實值,并返回替換后的字符串。

            應用場合:欲查看某一參數(shù)的值,可使用該函數(shù)。

            舉例:客服3.0工作流系統(tǒng),生成工單時打開工單頁面準備工單提交,提交之前想查看已通過關(guān)聯(lián)保存的serialNo參數(shù)的值。方法如下:

            lr_output_message(lr_eval_string("TheserialNo is {serialNo}"));

            注意點:如果不存在該參數(shù),將把“{參數(shù)名}”當作普通字符串輸出。如本例,如果不存在serialNo參數(shù),則輸出:The serialNo is {serialNo}。

            3.2.3.驗證點

            3.2.3.1.web_reg_find

            功能:在HTML文檔中查找指定的字符串。

            應用場合:該函數(shù)是檢查點函數(shù),在腳本中需要插入檢查點的地方使用。

            舉例:客服3.0工作流系統(tǒng),提交工單生成后,需要驗證工單是否提交成功。則可根據(jù)頁面提示“工單生成成功”進行驗證。在提交生成工單步驟前插入:

            web_reg_find("Text=工單生成成功",LAST);

            注意點:該函數(shù)是注冊型參數(shù),需要在請求服務器數(shù)據(jù)步驟之前插入該函數(shù)。與該函數(shù)功能類似的函數(shù)是web_find,但是web_find只對HTML方式的腳本起作用,對URL方式腳本則不起作用,而且web_find函數(shù)效率低下,已被廢棄。

            3.2.3.2. web_image_check

            功能:判斷某一個圖片是否存在HTML頁面中。

            應用場合:同web_reg_find函數(shù)一樣,該函數(shù)也是檢查點函數(shù),在腳本中需要插入檢查點的地方使用。

            舉例:客服3.0培訓考試系統(tǒng)并發(fā)測試,50個人同時打開試卷,為了驗證打開試卷成功,根據(jù)試卷中的圖片public/images/onexam.gif進行驗證:

            web_image_check("web_image_check","Src=public/images/onexam.gif",LAST);

            注意點:要使該函數(shù)生效,需要在runtime-seting中將打開。與web_reg_find不一樣的是,該函數(shù)不是注冊型函數(shù),因此需要在請求返回步驟之后插入該函數(shù)。上文提過,LoadRunner只能識別文本,因此web_image_check函數(shù)其本質(zhì)仍然是文本驗證,完全可以用web_reg_find替代,而且強烈推薦使用web_reg_find作為檢查點函數(shù)。

            3.2.4.日志輸出

            3.2.4.1. lr_output_message

            功能:將VUser的消息打印到日志文件和輸出窗口中,打印的消息帶有腳本行信息。

            應用場合:方便查看運行信息,輔助問題定位。

            舉例:客服3.0系統(tǒng),登錄工號已經(jīng)參數(shù)化,調(diào)試腳本時將當前的登錄工號輸出到Replay Log窗口中。代碼如下:

            lr_output_message("Thestaffno is %s",lr_eval_string("{staffno}"));

            注意點:與該函數(shù)具有類似功能的還有:lr_debug_message,lr_log_message lr_message,lr_error_message它們之間的不同之處這里不作詳細介紹,請參見LoadRunner幫助文檔。

            3.2.4.2. lr_vuser_status_message

            功能:將VUser的消息輸出到場景運行的VUser狀態(tài)窗口。

            應用場合:將一些關(guān)鍵信息輸出到VUser運行狀態(tài)窗口,方便場景執(zhí)行時查看。

            舉例:在場景運行過程中,出現(xiàn)了錯誤。根據(jù)錯誤窗口提示,該錯誤屬于VUser ID為2的虛擬用戶,為了方便將系統(tǒng)登錄用戶名與VUser ID對應起來,以方便問題定位。可以使用以下代碼:

            lr_vuser_status_message("Thelogin username is %s", lr_eval_string("{username}"));

            場景執(zhí)行時,可方便查看到VUserID與登錄用戶名的對應關(guān)系,如下圖:

            注意點:無

          3.2.5.其它實用函數(shù)

            3.2.5.1. lr_get_vuser_ip

            功能:獲得VUser的IP地址。

            應用場合:在使用IP欺騙時,為了驗證IP欺騙是否成功,可以使用該函數(shù)。

            舉例:在場景運行過程中,將每一個VUser的IP在VUser運行狀態(tài)窗口中顯示出來。

          char *ip;
          ip = lr_get_vuser_ip();
          if (ip)
          {
          lr_vuser_status_message("The IP addressis %s", ip);
          }

            注意點:為了使IP欺騙成功,使用IP欺騙向?qū)гO(shè)置好IP后,還要將打開才可。

            3.2.5.2. lr_load_dll

            功能:加載外部DLL。

            應用場合:腳本需要使用外部DLL時,使用該函數(shù)加載DLL。

            舉例:函數(shù)getDateTime(char * time,int seconds,char * resultTime)已封裝在timeutil.dll中,getDateTime的功能是根據(jù)傳入的日期字符串time(如2008-09-24 16:56:24),秒偏移量seconds,計算返回結(jié)果日期字符串resultTime,代碼如下:

          int hours =atoi(lr_eval_string("hours"));
          char acceptEndTime[20];
          lr_load_dll("../timeutil.dll");
          getDateTime(lr_eval_string("{acceptBeginTime}"),3600*hours,acceptEndTime);

            注意點:該函數(shù)為LoadRunner提供了調(diào)用外部接口的能力。

            3.3.封裝,構(gòu)建可重用腳本

            3.3.1.簡單函數(shù)封裝

            LoadRunner使用C語言作為腳本,因此只要是合法的C代碼都可以在LoadRunner中運行。為了提高腳本可讀性和腳本生產(chǎn)效率,有必要將性能測試腳本模塊化。

            客服3.0工作流系統(tǒng),查詢工單池是一個很常見的操作。我們可以把查詢工單池操作封裝為一個queryTTPool函數(shù),函數(shù)體如下,在腳本中,將所有的查詢工單池操作替換為queryTTPool函數(shù)調(diào)用,提高了腳本的可讀性:

          //查詢工單池
          int queryTTPool(char* nodeType){
          lr_save_string(nodeType,"nodeType");
          lr_save_datetime("%Y-%m-%d 00:00",DATE_NOW-2*ONE_DAY, "acceptBeginTime");
          lr_save_datetime("%Y-%m-%d 23:59", DATE_NOW,"acceptEndTime");
          lr_start_transaction("WF_查詢工單池工單");
          web_submit_data("IWFController",
          "Action=http://{wf_sysurl}/IWFController",
          "Method=POST",
          "RecContentType=text/html",
          "Referer=http://{wf_sysurl}/iwflow/common/UnitQueryDealForm.jsp?pageNo=1",            "Snapshot=t32.inf",
          "Mode=HTML",
          ITEMDATA,
          "Name=ACTIONID","Value=UniteQueryDealAction", ENDITEM,
          "Name=pageNo", "Value=1", ENDITEM,
          "Name=sortType", "Value=", ENDITEM,
          "Name=sortField", "Value=", ENDITEM,
          "Name=reSortFlag", "Value=", ENDITEM,
          "Name=acceptPhone", "Value=", ENDITEM,
          "Name=serialNo", "Value=", ENDITEM,
          "Name=serialFlag", "Value=0", ENDITEM,
          "Name=serviceName", "Value=", ENDITEM,
          "Name=serviceID", "Value=", ENDITEM,
          "Name=acceptBeginTime","Value={acceptBeginTime}", ENDITEM,
          "Name= acceptEndTime ", "Value={acceptEndTime}",ENDITEM,
          "Name=urgentID", "Value=", ENDITEM,
          EXTRARES,
          "Url=/iwflow/image/kms-1_23.gif", ENDITEM,
          "Url=/iwflow/buttons/obtainProcess-2.gif", ENDITEM,
          LAST);
          lr_end_transaction("WF_查詢工單池工單",LR_AUTO);
          }

            3.3.2.DLL封裝

            使用DLL有很多好處。高度重用的函數(shù)制作成DLL,方便腳本調(diào)用。將與IVR交互的消息函數(shù)封裝成DLL后,便可利用LoadRunner測試IVR性能。制作DLL可以選擇VC或者MinGW Developer Studio等工具,至于DLL的制作細節(jié),本文不作介紹,請參見相關(guān)指導書。

            4   腳本調(diào)試

            LoadRunner的VUser Generator本身的調(diào)試功能比較弱,只能設(shè)置斷點,無法單步跟蹤。當腳本出現(xiàn)問題時,可以使用lr_debug_message,lr_output_message,lr_eval_string等函數(shù)協(xié)助定位。

            腳本錯誤大部分原因都是向服務器發(fā)送的數(shù)據(jù)不對,因此還可以利用HttpAnalyzer工具進行HTTP協(xié)議跟蹤,通過比較LoadRunner發(fā)送的數(shù)據(jù)和瀏覽器發(fā)送的數(shù)據(jù),便能很快定位出問題根源。



          posted on 2013-09-23 10:51 順其自然EVO 閱讀(1700) 評論(0)  編輯  收藏 所屬分類: loadrunner

          <2013年9月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 南雄市| 方城县| 兴安盟| 铜鼓县| 依安县| 娱乐| 揭阳市| 尉氏县| 鄯善县| 福安市| 谢通门县| 景德镇市| 鱼台县| 宁南县| 芜湖县| 黄冈市| 信阳市| 衡东县| 古田县| 垣曲县| 娄烦县| 工布江达县| 砚山县| 偃师市| 巍山| 乳源| 射洪县| 固阳县| 金秀| 荣成市| 襄垣县| 田东县| 黎川县| 墨脱县| 包头市| 聊城市| 武宣县| 内江市| 家居| 邯郸市| 晋江市|