背景
最近項目要做性能測試,要出要一份性能報告,讓我出一個有關Tcp和Udp的功能模塊的測試,流程大概是這樣,先走TCP協議協商一下會話,協商成功后走Udp收發數據。
有點簡單啊,自己寫個功能模塊測一下,然后把結果展示出來就ok了。
然而想法很美好,現實有點殘酷。idea瞬間被pass掉,理由就是自己寫的測試模塊木有說服力。
要用專業的測試工具來搞,才有說服力。作為一名開發,用測試工具是不可能的,就算餓死也不會用!!!
最后還是學了一下LoadRunner,在歷經一番坎坷摸索之后,出了個測試腳本。不得不說,LR真的挺好用的。(PS:真香現場)
不說廢話了,在網上找了一下使用LR測試TCP和UDP的腳本,資料有點難找,大多都是簡單概況一下。(讓我一個LR初手,搞不定啊),最后在自己一番摸索之下,把過程整理一下,要有啥不好的地方,還請多指教一下。
准備工作
- LoadRunner 環境,這個大家自行百度,教程太多我就不詳說了
- 數據包,客戶端進行TCP協商的數據包,使用udp發送的數據包(用wireshark抓取)
- LR的測試腳本
編寫測試腳本
使用LR測試TCP和UDP要使用LR中Windows sockets協議,它可以模擬tcp/ip協議和服務器進行數據交互,這樣便可以模擬終端來進行性能測試了。首先打開LR Virtual User Generator選擇創建腳本。
圖:創建腳本
選擇創建windows sockets協議的腳本。
圖:選擇socket協議
接着會出來一個錄制選項框,在應用類型里有兩種選擇,一種是win32的應用,一種是瀏網絡應用,選擇后可以開始錄制腳本,會啟用對應的應用,根據操作錄制腳本。
圖:初始化參數
我這邊使用網絡應用,輸入要測試服務的URL,選擇對應的action,然后點擊ok就可以開始錄制。
這里可以選擇的活動對應有三種
- vuser_init:創建虛擬用戶初始化時做的事情, 比如要測試業務某個具體業務操作環節時,可以先把系統用戶登錄的寫在init中。
- action: 用戶操作的事件,即需要測試業務操作點。
- vuser_end:虛擬用戶退出的時候做到操作,如關閉socket等。
不過錄制腳本這個功能生成的測試腳本有的時候不符合我們的預期,還是要自己修改,所以我這里隨便錄制了一下,然后重寫腳本。
圖:結束錄制
點擊結束錄制,會生成腳本,如下圖,然后我們就可以自己修改腳本了。
最后就是最關鍵的地方了,根據具體業務流程來編寫測試腳本,我這里總體業務流程大致如下
編寫vuser_init
我這里由於要協商會話,所以在初始化時需要發送兩次請求和接受兩次請求,腳本如下
vuser_init() { char*recvbuf; int recvlen=0; int rc=0; lrs_startup(257); //設定開始事務 lr_start_transaction("Trans_Session"); lr_start_transaction("Conn_TCP"); //創建socket rc=lrs_create_socket("socket0","TCP","LocalHost=0","RemoteHost=127.0.0.1:8888",LrsLastArg); //判斷套接字創建是否成功 if(rc!=0){ lr_end_transaction("Conn_TCP",LR_FAIL); lr_end_transaction("Trans_Session",LR_FAIL); return 0; } lr_end_transaction("Conn_TCP",LR_PASS); //判斷socket是否鏈接成功的事務,0表示創建成功 lrs_send("socket0","senCreateReqBuf",LrsLastArg); //發送安全會話建立請求,senCreateReq為在data.ws中定義的發送變量 lrs_receive("socket0","senCreateRspBuf",LrsLastArg); //接收消息,存放在senCreateReq中,senCreateReq是在data.ws中定義的接收數組,注意數組長度一定要大於等於實際接收長度 lrs_get_last_received_buffer("socket0",&recvbuf,&recvlen);//把Socket最后接收的字節數組,長度放在recvlen中,內容放在recvbuf中 if(recvlen<100) { lr_end_transaction("Trans_Session",LR_FAIL); } lrs_send("socket0","authReqBuf",LrsLastArg); //發送authRsp,authRsp為在data.ws中定義的發送變量 lrs_receive("socket0","authRspBuf",LrsLastArg); //接收消息,存放在authRep中,authRep是在data.ws中定義的接收數組,注意數組長度一定要大於等於實際接收長度 lrs_get_last_received_buffer("socket0",&recvbuf,&recvlen);//把Socket最后接收的字節數組,長度放在recvlen中,內容放在recvbuf中 if(recvlen>60) lr_end_transaction("Trans_Session",LR_PASS); else lr_end_transaction("Trans_Session",LR_FAIL); return 0; }
1. 首選創建相關測試的事務,在性能測試中這個可以作為測試用例通過的依據lr_start_transaction與lr_end_transaction 為使用最多的事物創造組合函數,lr_start_transaction為事物開始函數,lr_end_transaction為事物結束函數,並負責記錄事物的運行時間.
語法格式如下:
- int lr_start_transaction (const char * transaction_name);
- int lr_end_transaction (const char * transaction_name,int status);
其中transacton為事物名稱,status為事物的結束狀態,共有LR_PASS(通過)、LR_FAIL(失敗)、LR_AUTO(自動)、 LR_STOP(暫停),其中LR_PASS默認的是LR_PASS,可以在事物結束前通過lr_set_transaction_status進行修改。如果在lr_end_transaction中沒有指定結束事物狀態是LR_AUTO,而是明確制定為LR_PASS、LR_FAIL、 LR_STOP其中的其中,則事物將以最后制定狀態來結束。需要注意,事物開始沒有lr_end_transaction沒有結束的時候,不能用相同的事 物名稱,除非這個事物已經通過lr_end_transaction結束。
2. 接着創建socket,初始化套接字,使用的函數如下
- int lrs_create_socket("socket0","TCP","LocalHost=0","RemoteHost=127.0.0.1:8888",LrsLastArg);
參數分別是:socket名稱、協議類型(TCP或UDP)、鏈接類型(遠程鏈接:RemoteHost、本地:LocalHost、或者本地監聽)、LrsLastArg 參數結束標記,創建成功返回0。
3. 創建完套接字后,判斷時候成功,若是失敗將對應的事務狀態修改為LR_FAIL。
4.通過socket發送數據,lrs_send("socket0","senCreateReqBuf",LrsLastArg); 這里senCreateReqBuf為待發送的數據,數據存在data.ws文件中。
send 后面填的是待發送數據buf的名稱,接着再跟上待發送數據的長度 ,待發送buf在LR中我這邊是以16進制發送,按照LR的規則需要在16進制值前中加上\x,很明顯構造這個數據還是麻煩的很。所以這里提供一個比較方便的方式。
我們可以從wireshark中直接抓取對應格式的數據,選擇需要的數據,右鍵復制,選擇轉義字符串,就可以了,最后將復制的數據放在data.ws中就可以了。
5.接收響應數據,判斷響應數據是否正確,我這里根據長度來判斷。
編寫Action
在Action文件中編寫需要測試的操作步驟,我這里就是發送udp請求,接受響應,判斷響應是否正確,代碼如下
Action() { char*recvbuf; int recvlen=0; int rc=0; lr_start_transaction("Trans_UDP"); lr_start_transaction("Conn_UDP"); rc=lrs_create_socket("socket1","UDP","RemoteHost=127.0.0.1:8887",LrsLastArg); if (rc != 0) { lr_end_transaction("Conn_UDP",LR_FAIL); lr_end_transaction("Trans_UDP",LR_FAIL); return 0; } lr_output_message("Received:%d",rc); lr_end_transaction("Conn_UDP",LR_PASS); lrs_send("socket1","ReqBuf",LrsLastArg); //發送ReqBuf,ReqBuf為在data.ws中定義的發送變量 lrs_receive("socket1","RspBuf",LrsLastArg); //接收消息,存放在RspBuf中,RspBuf是在data.ws中定義的接收數組,注意數組長度一定要大於等於實際接收長度 lrs_get_last_received_buffer("socket1",&recvbuf,&recvlen);//把Socket最后接收的字節數組,長度放在recvlen中,內容放在recvbuf中 if(recvlen>=128) { lr_end_transaction("Trans_UDP",LR_PASS); } else { lr_log_message("Error UDP Received length:%d",recvlen); lr_end_transaction("Trans_UDP",LR_FAIL); }
//--------------斷開socket-------------- lrs_disable_socket("socket1",DISABLE_SEND_RECV); //--------------關閉socket-------------- lrs_close_socket("socket1"); return 0; }
原理和上文提的基本一致,這里就不再多說了
編寫vuser_end
編寫結束時的操作,這里就是關閉init中的socket
vuser_end() { //--------------斷開socket-------------- lrs_disable_socket("socket0", DISABLE_SEND_RECV); //--------------關閉socket-------------- lrs_close_socket("socket0"); return 0; }
運行測試腳本
點擊start,執行腳本,運行無誤,說明腳本正確
至此測試腳本編寫完畢,可以正式開始性能測試了
性能測試
- 始運行LR執行性能測試
- 這里我們將剛剛編寫好的的測試腳本添加進去
- 然后配置相關的測試參數,如並發數,測試時間等,開始測試
- 觀察測試結果
最后在運行結束后,我們可以根據分析報告診斷性能測試結果,還可以配合jvisualvm工具診斷熱點方法,提升程序性能
總結
我們可以LR可以配合jvisualvm工具診斷熱點方法,提升程序性能。如果有大神看出什么端倪的話,歡迎批評斧正,個人感覺還有提升空間