804
windows
手工腳本編寫指南__手工腳本編寫_Lite用戶使用手冊_性能測試-阿裏雲
手工編寫測試腳本
1.概述
Lite代碼模式可以使用自定義代碼實現更加豐富的壓測行為,比如TCP、UDP協議,豐富的API讓您變的無所不能;Lite所使用的腳本語言為Jython,Jython是Python的Java語言實現,它使用Python的語法和類庫,運行在JVM中,和同一個JVM中的Java類可以實現無縫互操作。因此,使用Jython作為腳本語言可以最大程度的利用Python的簡潔、高效,同時保留對Java語言的全麵兼容。
Lite為了使腳本的創建更加高效,通過模板模式或錄製工具提供配置式和錄製式編寫HTTP測試腳本的功能。用戶在頁麵上配置的HTTP腳本在執行前會被自動轉換成Jython腳本,用戶可以通過預覽或者手工編輯查看自動轉換後的腳本代碼內容。通過模板模式和錄製工具來編寫HTTP腳本非常方便,但是如果遇到一些比較複雜的業務場景,比如定製化的用戶登錄,可配置的執行流程或者需要對請求進行動態關聯等等,就需要用戶通過手工編寫腳本的方式來實現測試邏輯。
本文圍繞在Lite中使用手工編寫方式這個主題,重點介紹性能測試腳本所用到的一些Jython語言基礎、測試腳本框架、常用類和函數,最後介紹一些常用的腳本功能範例。用戶通過閱讀該指南能夠在Lite中手工編寫較為複雜的性能測試腳本。
2.Jython語法基礎
2.1語言基礎
本章節重點介紹和編寫性能測試腳本相關的Jython語言基礎,內容非常有限。讀者如果需要更全麵、深入地解Jython語言可以首先參考Python的Tutorial,語言Reference和Jython的用戶手冊。
2.2Jython的詞法
Jython程序是由一係列語句組成的,語句組成了代碼塊,代碼塊組成了方法、函數,然後再通過類把數據、方法和函數封裝起來。和其它高級語言一樣,Jython的語句也是有一些最基本的詞(token)組成的。Token可以是標識符(identifiers)、關鍵字(keywords)、字麵值(literals)、操作符(operators)和分割符(delimiters)。這些token通過Jython的語言執行器進行詞法分析產生,而詞法分析器通過字符方式讀入Jython腳本文件,這時就涉及到文件編碼問題。
2.3文件編碼
Jython默認以ASCII碼(Latin-1)的方式讀入腳本文件,如果你的文件中存在非7位ASCII編碼的字符就會發生錯誤。我們通過在腳本文件首行添加以下代碼來讓Jython分析器知道用那種編碼來讀入腳本文件:
# -*- coding: utf-8 -*-
以上指示表示該Jython腳本的編碼為UTF-8,這樣我們就可以在腳本中使用中文這樣的Unicode字符。
2.4代碼行
Jython腳本由邏輯代碼行組成,邏輯行可以是一個物理行,也可以是多個物理行通過顯式或隱式連接起來的。而物理行就是文件中以NEWLINE結尾的行,NEWLINE在不通的平台上各有不一,比如UNIX係統中以LF(linefeed)作為換行,Windows中已(CRLF)作為換行而Mac中以CR作為換行,這些換行符在Jython中都支持。
if 1900 < year < 2100 and 1 <= month <= 12
and 1 <= day <= 31 and 0 <= hour < 24
and 0 <= minute < 60 and 0 <= second < 60: # Looks like a valid date
return 1
顯示連接用在一行語句太長,需要分多行顯示的情況,我們可以通過’’,反斜杠來將多個行連接成一條語句:
month_names = ['Januari', 'Februari', 'Maart', # These are the
'April', 'Mei', 'Juni', # Dutch names
'Juli', 'Augustus', 'September', # for the months
'Oktober', 'November', 'December'] # of the year
2.4代碼塊
代碼塊可以是一個類,一個方法/函數,或者是一個if/while的控製單元。多數程序語言會用專門的開始結束標誌來表示一個代碼塊,但是Jython/Python卻通過縮進來表示一個代碼塊,這是初學Python的人最不適應的地方。縮進可以使用空格或者Tab製表符,但是最後Jython在解析的時候會將Tab轉換成空格,而不通的機器Tab和空格的對應關係可能不一樣,比如Windows通常使用4個空格表示一個Tab,而Unix可能用8個空格。
所以非常重要的是我們在編輯器中隻使用一種縮進方式:要不都用空格,要不都用縮進。我的通常做法是打開Eclipse的Tab自動轉空格功能,在本地編輯就直接都用空格來縮進Jython腳本。開啟一個代碼塊需要用‘:’來提示。
正確的示範:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
錯誤的示範:
def perm(l): # error: first line indented
for i in range(len(l)): # error: not indented
s = l[:i] + l[i+1:]
p = perm(l[:i] + l[i+1:]) # error: unexpected indent
for x in p:
r.append(l[i:i+1] + x)
return r # error: inconsistent dedent
2.5標識符
ython的標識符(類名、變量名等)隻能以下劃線或者字母開頭,後麵跟字母、數字或者下劃線,其他任何字符都是非法的標識符。標識符區分大小寫、類和方法。
用戶可以定義一個類把數據和操作封裝起來。比如下麵這段代碼定義了一個TestRunner的類,這個類有4個方法:init、call、action_20013805。Jython定義方法用到關鍵字def,一般”雙劃線”格式的方法都是語言內置的特殊方法,比如init方法是類的初始化方法,當一個類被實例化的時候該方法會被用調用一次,來初始化類的一些成員數據;call方法用來實現一個類的callable接口,這個一般會在多線程調用時用到。
Lite用來測試的業務主體也是寫在這個方法裏麵,這樣就可以多次循環的調用業務邏輯。del方法類似Java的finalize方法,通常在類的對象消亡之前執行一些銷毀操作,但是這個並不是實時的。
class TestRunner:
# TestRunner對象的初始化方法,每個線程在創建TestRunner後執行一次該方法
def __init__(self):
self.threadContext = PTS.Context.getThreadContext()
# 主體壓測方法,每個線程在測試生命周期內會循環調用該方法
def __call__(self):
PTS.Data.delayReports = 1
statusCode = self.action_20013805()
PTS.Framework.setExtraData(statusCode)
PTS.Data.report()
PTS.Data.delayReports = 0
def __del__(self):
self.end = u'結束'
def action_20013805(self):
statusCode = [0L, 0L, 0L, 0L]
headers = []
result = HTTPRequest().GET(u'https://xx.xx.xx.xx:8080/examples/servlets/servlet/RequestInfoExample',[],headers)
PTS.Framework.addHttpCode(result.getStatusCode(), statusCode)
if(300 <= result.getStatusCode()):
PTS.Data.forCurrentTest.success = False
return statusCode
# 調用施壓引擎施壓。第一個參數是事務名,可以為中文;第二個參數是執行事務方法的方法名;第三個統一寫TestRunner
PTS.Framework.instrumentMethod(u'requestInfo', 'action_20013805', TestRunner)
看上麵這段代碼,我們還注意到Jython與Java或者C這些強類型語言的一些區別:變量的申明不需要指定類型,同樣方法或者函數的入參和返回值也不需要製定類型,這就是Jython/Python語言的另一大特性——弱類型,Jython執行器隻有在執行的時候才回去判斷對象的類型,如果有不匹配的操作會拋出異常。
細心的讀者還會發現一個怪怪的self,其實self就類似Java語言中的this,通過self類中的方法/函數可以引用類的成員變量,或者調用類的成員方法,如果不加self,則默認使用全局空間的變量或方法,所謂全局變量/方法就是定義在類之外,腳本中頂格寫的變量或者方法。定義類成員函數時,必須把self作為第一個參數傳遞給所定義的方法。
2.6字符串
Jython中的字符串是被單引號、雙引號引起來的字符集,單引號括起來的字符串中可以包含雙引號而不需要用轉義,同樣,雙引號重的單引號也不需要轉義。
比如:s = ‘This is a “BIG” surprise!’,這個是一個合法的字符串。字符串作為一種特殊的字符數組,支持下標操作,比如s[0]=’T’,s[0:5]=’This’。
字符串還有很多其它的操作比如連接、比較、分割,可以參考: https://docs.python.org/2/tutorial/introduction.html#strings
2.7列表
Jython中用[]來表示一個列表,列表是可變的,比如: a = [‘apple’, ‘orange’, ‘peach’]
數組下標從0開始,a[0]=’apple’;a[1]=’orange’。獲列表長度用Jython內置函數:len,比如len(a)=3。
更多列表操作,請參考:https://docs.python.org/2/tutorial/introduction.html#lists
2.8腳本的執行
Jython是解釋執行語言,所以一個腳本被Jython引擎分析後,是按行執行的。腳本中頂格的代碼行都是會被執行器執行的,而類或者全局方法則會被定義,定義之後代碼中其他的地方可以使用這些類和方法。
1.一般腳本的前幾行都是用來注釋和作指引(比如字符編碼):
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# PTS Script Version 1.0
# Trunner auto-generated test script at Mon Jul 13 17:57:10 CST 2015
2.接下去回有一些import語句來導入腳本中所用的地其它類或者模塊: Jython中的模塊(Module)類似Java中的Package,用來把一組功能耦合的類封裝在一起。由於Jython可以和Java會操作,所以這裏的import語句也可以直接導入Java的package或者類。比如:
from java.lang import String
from java.util import Random
from java.util import Date
# PTS腳本SDK:框架API、常用HTTP請求/響應處理API
from util import PTS
from HTTPClient import NVPair
from HTTPClient import Cookie
from HTTPClient import HTTPRequest
from HTTPClient import CookieModule
from HTTPClient import ShutdownException
3.然後可以在腳本中定義一些類或者方法:
class TestRunner:
# TestRunner對象的初始化方法,每個線程在創建TestRunner後執行一次該方法
def __init__(self):
# 主體壓測方法,每個線程在測試生命周期內會循環調用該方法
def __call__(self):
def __del__(self):
def action_20013805(self):
4.也可以執行一些語句:
# 腳本初始化段,可以設置壓測引擎的常用HTTP屬性ttt
PTS.HttpUtilities.setUrlEncoding('UTF-8')
PTS.HttpUtilities.setFollowRedirects(True)
PTS.HttpUtilities.setTimeout(120000)
# PTS.HttpUtilities.setKeepAlive(False)
# PTS.HttpUtilities.setUseCookieModule(False)
# PTS.HttpUtilities.setProxyServer('localhost', 8888)
# PTS.Context.setParamDirectory("/Users/fei/Work/trunner/data")
3腳本框架
Lite的代碼腳本是一個TestRunner類,這個類會被每一個並發線程初始化,類成員變量是線程安全的。測試進程首先加載腳本,並且執行腳本中頂格的語句,同時定義了TestRunner這個測試類;然後每個線程會實例化一個TestRunner類,調用類中的init方法一次,繼而循環調用TestRunner類的call方法;最後線程結束時,會調用類中的del方法。init和del方法都是可選的,隻有call方法是必需的。
所以一個Lite代碼腳本的總體框架如下:
第一部分:執行器聲明和腳本編碼聲明及腳本創建信息
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# PTS Script Version 1.0
# Trunner auto-generated test script at Mon Jul 13 17:57:10 CST 2015
第二部分:Jython類庫、Java類庫和自定義類的導入
from java.lang import String
from java.util import Random
from java.util import Date
# PTS腳本SDK:框架API、常用HTTP請求/響應處理API
from util import PTS
from HTTPClient import NVPair
from HTTPClient import Cookie
from HTTPClient import HTTPRequest
from HTTPClient import CookieModule
from HTTPClient import ShutdownException
# 支持socket測試, 如TCPUDP等協議
# import socket
# 設置係統編碼
import sys
第三部分:測試進程級別的腳本語句和初始化
# 腳本初始化段,可以設置壓測引擎的常用HTTP屬性ttt
PTS.HttpUtilities.setUrlEncoding('UTF-8')
PTS.HttpUtilities.setFollowRedirects(True)
PTS.HttpUtilities.setTimeout(120000)
# PTS.HttpUtilities.setKeepAlive(False)
# PTS.HttpUtilities.setUseCookieModule(False)
# PTS.HttpUtilities.setProxyServer('localhost', 8888)
# PTS.Context.setParamDirectory("/Users/fei/Work/trunner/data")
第四部分:TestRunner測試類
class TestRunner:
# TestRunner對象的初始化方法,每個線程在創建TestRunner後執行一次該方法
def __init__(self):
self.threadContext = PTS.Context.getThreadContext()
# 主體壓測方法,每個線程在測試生命周期內會循環調用該方法
def __call__(self):
PTS.Data.delayReports = 1
statusCode = self.action_20013805()
PTS.Framework.setExtraData(statusCode)
PTS.Data.report()
PTS.Data.delayReports = 0
def action_20013805(self):
statusCode = [0L, 0L, 0L, 0L]
headers = []
result = HTTPRequest().GET(u'https://xx.xx.xx.xx:8080/examples/servlets/servlet/RequestInfoExample',[],headers)
PTS.Framework.addHttpCode(result.getStatusCode(), statusCode)
if(300 <= result.getStatusCode()):
PTS.Data.forCurrentTest.success = False
return statusCode
第五部分:Instrument語句
# 調用施壓引擎施壓。第一個參數是事務名,可以為中文;第二個參數是執行事務方法的方法名;第三個統一寫TestRunner
PTS.Framework.instrumentMethod(u'requestInfo', 'action_20013805', TestRunner)
最後更新:2016-05-06 10:44:42
上一篇:
錄製測試腳本__腳本開發_Lite用戶使用手冊_性能測試-阿裏雲
下一篇:
Lite腳本編寫SDK__手工腳本編寫_Lite用戶使用手冊_性能測試-阿裏雲
查詢可用區__地域相關接口_API 參考_雲服務器 ECS-阿裏雲
阿裏雲棲大會超詳幹貨:馬雲投入千億成立達摩院,要比阿裏活更久
API指南__開發者指南_公眾趨勢分析-阿裏雲
阿裏雲歸檔存儲簡介__API使用手冊_歸檔存儲-阿裏雲
資源查詢場景__場景示例_Open API_消息隊列 MQ-阿裏雲
創建自定義監控項和報警規則__自定義監控_用戶指南_雲監控-阿裏雲
SDK示例代碼運行簡介__數據訂閱_用戶指南_數據傳輸-阿裏雲
HTTP 協議規範__HTTP 接入(簡單)_消息隊列 MQ-阿裏雲
虛擬主機顯示站點隱藏配置文件方法___安全問題_技術分享_雲虛機主機-阿裏雲
解析記錄衝突判斷規則__附錄_API文檔_雲解析-阿裏雲
相關內容
常見錯誤說明__附錄_大數據計算服務-阿裏雲
發送短信接口__API使用手冊_短信服務-阿裏雲
接口文檔__Android_安全組件教程_移動安全-阿裏雲
運營商錯誤碼(聯通)__常見問題_短信服務-阿裏雲
設置短信模板__使用手冊_短信服務-阿裏雲
OSS 權限問題及排查__常見錯誤及排除_最佳實踐_對象存儲 OSS-阿裏雲
消息通知__操作指南_批量計算-阿裏雲
設備端快速接入(MQTT)__快速開始_阿裏雲物聯網套件-阿裏雲
查詢API調用流量數據__API管理相關接口_API_API 網關-阿裏雲
使用STS訪問__JavaScript-SDK_SDK 參考_對象存儲 OSS-阿裏雲