本申請涉及web service技術(shù)領(lǐng)域,具體涉及一種web service壓力測試方法。本申請同時涉及一種web service壓力測試裝置。
背景技術(shù):
Web service(web服務(wù))是一種跨編程語言和跨操作系統(tǒng)平臺的遠程調(diào)用技術(shù),它是目前比較流行的一種平臺獨立的、低耦合的、自包含的、基于可編程的web的應(yīng)用程序。web service的三要素是:SOAP(Simple Object Access Protocol—簡單對象訪問協(xié)議)、WSDL(Web Services Description Language—web service描述語言)、以及UDDI(Universal Description Discovery and Integration—統(tǒng)一描述、發(fā)現(xiàn)和集成)。其中,WSDL是基于XML的web service描述語言,用于描述web service及其提供的接口函數(shù)(或者方法)、參數(shù)和返回值;而SOAP則是基于http等協(xié)議的、用于在應(yīng)用程序之間進行通信的一種通信協(xié)議。通常,希望使用web service服務(wù)的客戶端根據(jù)WSDL提供的服務(wù)接口信息,遵循SOAP協(xié)議調(diào)用web service服務(wù)端提供的接口函數(shù)即可完成特定的服務(wù)調(diào)用,實現(xiàn)所需的功能。
在實際應(yīng)用中,在開放web service服務(wù)之前通常需要進行嚴格的壓力測試,以獲知web service所能承受的最大訪問量,并驗證web service在大訪問量情況下功能的正確性。目前業(yè)內(nèi)主流的壓力測試工具(簡稱壓測工具)主要包括JMeter、LoadRunner等。其中,LoadRunner是一種預(yù)測系統(tǒng)行為和性能的測試工具,需要使用其自己的腳本語言完成SOAP協(xié)議報文的發(fā)送功能;JMeter是Apache組織開發(fā)的基于Java的開源壓測工具,采用多線程模擬并發(fā)訪問量,通常也是通過發(fā)送SOAP協(xié)議報文實現(xiàn)壓力測試功能,請參見圖1所示的JMeter工具的圖形用戶界面的示意圖,其中采用黑色粗線框標注的、名稱為“Soap/XML-RPC Data”的文本區(qū)域中的內(nèi)容就是測試人員輸入的部分SOAP協(xié)議報文。
在具體應(yīng)用中,LoadRunner工具由于使用自定義腳本給壓測人員增加了額 外的學(xué)習(xí)成本,而且web service服務(wù)的參數(shù)在SOAP報文中實現(xiàn)參數(shù)化難度很大,此外,通過上面的描述可以看出,目前主流的壓測工具都是通過網(wǎng)絡(luò)協(xié)議來測試web service服務(wù),在實際應(yīng)用中通常需要通過網(wǎng)絡(luò)抓包的方式截取SOAP報文,并進行協(xié)議解析以及相應(yīng)的修改以生成所需的SOAP報文。由于SOAP報文遵循標準的協(xié)議規(guī)范,因此這種通過網(wǎng)絡(luò)層來模擬壓測調(diào)用的方式均有較高的學(xué)習(xí)成本,不僅對測試人員提出了較高的要求,而且由于操作步驟繁瑣可能會影響壓力測試的整體效率。
技術(shù)實現(xiàn)要素:
本申請?zhí)峁┮环Nweb service壓力測試方法,以解決現(xiàn)有的壓測工具采用基于SOAP報文的方式進行壓力測試導(dǎo)致學(xué)習(xí)成本高、操作繁瑣的問題。本申請另外提供一種web service壓力測試裝置。
本申請?zhí)峁┮环Nweb service壓力測試方法,包括:
獲取被測web service的配置信息、以及按照預(yù)先設(shè)定的方式執(zhí)行web service服務(wù)調(diào)用的測試代碼;
在預(yù)處理階段,修改并編譯所述測試代碼,得到可執(zhí)行的測試代碼;所述修改是指將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用,其中,所述客戶端封裝了支持web service服務(wù)調(diào)用的協(xié)議;
在測試執(zhí)行階段,每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
可選的,所述被測web service的配置信息包括:被測服務(wù)名稱、被測方法名稱、以及被測web service的URL信息。
可選的,在所述預(yù)處理階段,還執(zhí)行下述操作:
根據(jù)所述被測web service的配置信息,初始化所述對應(yīng)于被測web service的客戶端和方法對象;
相應(yīng)的,所述每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù)是指,每個測試線程使用上述在預(yù)處理階段已初始化的客戶端和方法對象作為入口參數(shù)。
可選的,所述方法以JMeter插件的形式實現(xiàn);
相應(yīng)的,所述被測web service的配置信息以及所述測試代碼是通過JMeter的圖形用戶界面獲取的;
所述預(yù)處理階段是指,JMeter中的前置處理階段。
可選的,在所述前置處理階段修改所述測試代碼還包括:
在所述測試代碼的入口參數(shù)中添加測試所需的自定義參數(shù);
用所述自定義參數(shù)替換所述測試代碼中的相應(yīng)參數(shù)化變量;
相應(yīng)的,在測試執(zhí)行階段,每個測試線程在調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)之前,執(zhí)行下述操作:
通過比對從所述圖形用戶界面獲取的測試代碼和由CSV組件進行參數(shù)替換后的測試代碼,獲取參數(shù)化變量被替換后的具體值;
相應(yīng)的,在測試執(zhí)行階段,每個測試線程調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)時,所使用的入口參數(shù)還包括:所述參數(shù)化變量被替換后的具體值。
可選的,所述根據(jù)入口參數(shù)提供的客戶端以及方法對象完成web service服務(wù)調(diào)用是指,根據(jù)入口參數(shù)提供的客戶端以及方法對象,通過反射方式完成web service服務(wù)調(diào)用。
可選的,在前置處理階段修改并編譯所述測試代碼之前,執(zhí)行下述操作:
將所述測試代碼所使用的第三方j(luò)ar包加載到對應(yīng)的類加載器中。
可選的,在所述前置處理階段修改所述測試代碼還包括:
修改所述測試代碼的返回語句,使其返回信息包括:執(zhí)行web service服務(wù)調(diào)用的入口參數(shù)信息、以及結(jié)果信息。
可選的,在測試執(zhí)行階段,每個測試線程調(diào)用所述可執(zhí)行的測試代碼后,執(zhí)行下述操作:
將所述調(diào)用操作返回的入口參數(shù)信息和結(jié)果信息,分別添加到JMeter結(jié)果樹的request屬性及response屬性中。
可選的,在前置處理階段修改并編譯所述測試代碼后,執(zhí)行下述操作:
將編譯后生成的.class文件顯示的加載至對應(yīng)的類加載器中;
根據(jù)顯示加載返回的類,通過反射機制初始化可執(zhí)行對象;
相應(yīng)的,所述在測試執(zhí)行階段,每個測試線程調(diào)用所述可執(zhí)行的測試代碼 完成測試任務(wù)是指,每個測試線程調(diào)用所述已初始化的可執(zhí)行對象,完成測試任務(wù)。
相應(yīng)的,本申請還提供一種web service壓力測試裝置,包括:
信息與代碼獲取單元,用于獲取被測web service的配置信息、以及按照預(yù)先設(shè)定的方式執(zhí)行web service服務(wù)調(diào)用的測試代碼;
測試預(yù)處理單元,用于在預(yù)處理階段,修改并編譯所述測試代碼,得到可執(zhí)行的測試代碼;所述修改是指將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用,其中,所述客戶端封裝了支持web service服務(wù)調(diào)用的協(xié)議;
測試執(zhí)行單元,用于在測試執(zhí)行階段,每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
可選的,所述信息與代碼獲取單元獲取的被測web service的配置信息包括:被測服務(wù)名稱、被測方法名稱、以及被測web service的URL信息。
可選的,所述測試預(yù)處理單元包括:
代碼修改子單元,用于修改所述測試代碼,所述修改是指將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用;
代碼編譯子單元,用于編譯修改后的測試代碼,得到可執(zhí)行的測試代碼;
所述測試預(yù)處理單元還包括:
客戶端初始化子單元,用于根據(jù)所述被測web service的配置信息,初始化所述對應(yīng)于被測web service的客戶端和方法對象;
相應(yīng)的,所述測試執(zhí)行單元具體用于,每個測試線程使用所述客戶端初始化子單元初始化的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
可選的,所述裝置以JMeter插件的形式實現(xiàn);
相應(yīng)的,所述信息與代碼獲取單元具體用于,通過JMeter的圖形用戶界面獲取所述被測web service的配置信息以及所述測試代碼。
可選的,所述代碼修改子單元除了包括:
服務(wù)調(diào)用修改子單元,用于將所述測試代碼修改為:根據(jù)入口參數(shù)提供的 客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用;
所述代碼修改子單元還包括:
自定義參數(shù)修改子單元,用于在所述測試代碼的入口參數(shù)中添加測試所需的自定義參數(shù);
參數(shù)化變量替換子單元,用于用所述自定義參數(shù)替換所述測試代碼中的相應(yīng)參數(shù)化變量;
相應(yīng)的,所述測試執(zhí)行單元除了包括:
服務(wù)調(diào)用子單元,用于每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù);
所述測試執(zhí)行單元還包括:
參數(shù)值獲取子單元,用于在觸發(fā)所述服務(wù)調(diào)用子單元之前,每個測試線程通過比對從所述圖形用戶界面獲取的測試代碼和由CSV組件進行參數(shù)替換后的測試代碼,獲取參數(shù)化變量被替換后的具體值;
相應(yīng)的,所述測試執(zhí)行單元所使用的入口參數(shù)還包括,所述參數(shù)值獲取子單元獲取的參數(shù)化變量被替換后的具體值。
可選的,所述測試執(zhí)行單元是通過反射方式完成web service服務(wù)調(diào)用的。
可選的,所述測試預(yù)處理單元還包括:
jar包加載子單元,用于在觸發(fā)所述代碼修改子單元之前,將所述測試代碼所使用的第三方j(luò)ar包加載到對應(yīng)的類加載器中。
可選的,所述代碼修改子單元還包括:
返回語句修改子單元,用于修改所述測試代碼的返回語句,使其返回信息包括:執(zhí)行web service服務(wù)調(diào)用的入口參數(shù)信息、以及結(jié)果信息。
可選的,所述測試執(zhí)行單元還包括:
返回信息處理子單元,用于將所述調(diào)用操作返回的入口參數(shù)信息和結(jié)果信息,分別添加到JMeter結(jié)果樹的request屬性及response屬性中。
可選的,所述測試預(yù)處理單元還包括:
類加載子單元,用于將所述代碼編譯子單元生成的.class文件顯示的加載至對應(yīng)的類加載器中;
可執(zhí)行對象初始化子單元,用于根據(jù)所述類加載子單元執(zhí)行加載操作返回 的類,通過反射機制初始化可執(zhí)行對象;
相應(yīng)的,所述測試執(zhí)行單元具體用于,每個測試線程調(diào)用所述已初始化的可執(zhí)行對象,完成測試任務(wù)。
與現(xiàn)有技術(shù)相比,本申請具有以下優(yōu)點:
本申請?zhí)峁┑膚eb service壓力測試方法,首先獲取被測web service的配置信息以及測試代碼,然后在預(yù)處理階段將所述測試代碼修改為根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用,并采用動態(tài)編譯的方式得到可執(zhí)行代碼,在測試執(zhí)行階段,每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。本技術(shù)方案由于內(nèi)置了支持web service服務(wù)調(diào)用相關(guān)協(xié)議的客戶端,因此提供測試代碼的測試人員無需了解網(wǎng)絡(luò)協(xié)議報文的細節(jié),也不用在協(xié)議報文層面進行編碼,而是可以采用其熟悉的編程語言、直接按照預(yù)先設(shè)定的方式進行web service服務(wù)調(diào)用即可,從而不僅降低了測試人員的學(xué)習(xí)成本,而且簡化了編寫測試代碼的工作量,同時也為測試過程的參數(shù)化提供了一種簡便途徑。
附圖說明
圖1是現(xiàn)有壓測工具JMeter提供的用于輸入web service壓測配置信息和SOAP報文的圖形用戶界面的示意圖;
圖2是本申請的一種web service壓力測試方法的實施例的流程圖;
圖3是本申請實施例提供的JMeter插件的配置界面的示意圖;
圖4是本申請實施例提供的前置處理階段的處理流程圖;
圖5是本申請實施例提供的在前置處理階段修改測試代碼的處理流程圖;
圖6是本申請實施例提供的每個測試線程執(zhí)行服務(wù)調(diào)用的處理流程圖;
圖7是本申請的一種web service壓力測試裝置的實施例的示意圖。
具體實施方式
在下面的描述中闡述了很多具體細節(jié)以便于充分理解本申請。但是本申請能夠以很多不同于在此描述的其它方式來實施,本領(lǐng)域技術(shù)人員可以在不違背 本申請內(nèi)涵的情況下做類似推廣,因此本申請不受下面公開的具體實施的限制。
在本申請中,分別提供了一種web service壓力測試方法,以及一種web service壓力測試裝置,在下面的實施例中逐一進行詳細說明。為了便于理解,先對本技術(shù)方案和實施例作簡要說明。
本技術(shù)方案提供的一種web service壓力測試方法,通過將測試代碼修改為根據(jù)入口參數(shù)提供的客戶端和方法對象執(zhí)行web service服務(wù)調(diào)用,并在測試階段調(diào)用編譯后的可執(zhí)行測試代碼,從而完成壓力測試。采用本技術(shù)方案,由于內(nèi)置了支持web service服務(wù)調(diào)用協(xié)議的客戶端,測試人員只需在測試代碼(也稱測試腳本)中直接調(diào)用被測web serivce提供的服務(wù)接口,而不用在協(xié)議報文層面進行編碼,從而可以有效減少測試人員對網(wǎng)絡(luò)協(xié)議的學(xué)習(xí)成本,簡化測試代碼的編寫工作,提高壓力測試的整體效率。
其中,所述客戶端封裝的支持web service服務(wù)調(diào)用的協(xié)議包括:簡單對象訪問協(xié)議SOAP(Simple Object Access Protocol)。SOAP是一種用于在應(yīng)用程序之間進行交互的通信協(xié)議,是web service三要素之一,其通過XML來實現(xiàn)消息描述、并通過HTTP等傳輸協(xié)議實現(xiàn)消息傳輸。當然,在具體實施中,本技術(shù)方案內(nèi)置的客戶端還可以封裝與web service服務(wù)調(diào)用相關(guān)的其他標準協(xié)議,只要所述客戶端能夠滿足測試人員的壓測需求,就同樣可以簡化測試人員的學(xué)習(xí)成本,減少編碼的工作量。
在實施本技術(shù)方案時,可以自行編寫封裝了上述web service協(xié)議的客戶端,也可以采用現(xiàn)有技術(shù)中已有的客戶端,從而簡化實施過程??紤]到XFire是新一代Web Service框架,不僅提供了簡單的API以支持Web Service體系中的各項標準協(xié)議和許多新的規(guī)范,并且提供多種客戶端調(diào)用方式。因此,本文描述的實施例提供了一種優(yōu)選實施方式,即采用XFire客戶端作為內(nèi)置客戶端實現(xiàn)本申請?zhí)峁┑募夹g(shù)方案。
在具體實施時,本申請?zhí)峁┑姆椒梢宰鳛橐粋€完整的技術(shù)方案獨立實現(xiàn),也可以從簡化實施過程的角度出發(fā),將上述方法作為已有測試工具的插件來實現(xiàn)??紤]到JMeter是目前測試人員通常使用的壓測工具之一,因此本實施例采用JMeter插件的形式實現(xiàn)本技術(shù)方案。其他測試工具如果可以像JMeter一樣提供開源的接口API調(diào)用,也可以在其他測試工具的基礎(chǔ)上、同樣采用動態(tài)編譯的思路實現(xiàn)本技術(shù)方案。
此外需要說明的是,本技術(shù)方案對于測試人員提供的測試代碼是采用何種計算機語言編寫的,并不做具體限定。在本實施例中,考慮到各種開發(fā)語言的應(yīng)用普及程度,所述測試代碼是采用Java語言編寫的,并且利用了Java的反射機制實現(xiàn)web service服務(wù)調(diào)用。在其他實施方式中,在具備相應(yīng)編譯工具的條件下,測試人員也可以提供用其他計算機語言編寫的測試代碼,例如同樣支持反射機制的objective-C,或者其他計算機語言,只要能夠支持根據(jù)入口參數(shù)傳入的客戶端和方法對象完成web service服務(wù)調(diào)用就同樣可以實現(xiàn)本技術(shù)方案。
下面對本實施例進行詳細描述。請參考圖2,其為本申請的一種web service壓力測試方法的實施例的流程圖。所述方法包括如下步驟:
步驟201:獲取被測web service的配置信息、以及按照預(yù)先設(shè)定的方式執(zhí)行web service服務(wù)調(diào)用的測試代碼。
在具體實施時,可以通過向測試人員展示圖形用戶界面,提示測試人員輸入被測web service的配置信息以及所述測試代碼(也稱測試腳本),也可以從測試人員提供的數(shù)據(jù)文件中讀取上述信息,從而完成本步驟的操作。
由于本實施例是以JMeter插件的形式實現(xiàn)的,因此在本步驟中可以從所述JMeter插件的取樣器(sampler)配置界面獲取被測web service的配置信息以及測試代碼。為了便于理解,先對采用JMeter插件進行壓力測試作簡要說明。
通過JMeter插件進行web service壓力測試,其基本原理是通過線程組模擬并發(fā)用戶對web service的訪問。首先,通過取樣器的配置界面獲取測試人員提供的被測web service的配置信息以及測試代碼等信息,隨后在初始化線程組執(zhí)行測試時,每個線程通過取樣器調(diào)用測試代碼,執(zhí)行向服務(wù)器發(fā)送請求并記錄服務(wù)器響應(yīng)信息的操作,從而完成一次測試。此外,在執(zhí)行測試之前,可以通過前置處理器(Per Processors)進行相關(guān)的準備工作,在測試任務(wù)完成后,可以通過后置處理器(Post Processors)進行必要的測試收尾工作。
本步驟通過所述JMeter插件的配置界面獲取的被測web service的配置信息包括:被測服務(wù)名稱、被測方法名稱、以及被測web service的URL信息。請參見圖3,其為本實施例提供的JMeter插件的配置界面的示意圖,測試人員可以在“WS服務(wù)配置”區(qū)域中提供被測web service的配置信息,其中,ws_url對應(yīng)文本框為被測web service的URL信息,serviceName對應(yīng)文本框為被測服務(wù)名稱,methodName對應(yīng)文本框為被測方法名稱,java code對應(yīng)文本框為用戶 提供的測試代碼。從該圖形用戶界面中還可以獲取測試人員設(shè)置的訪問服務(wù)器的超時時間timeout。
由于本技術(shù)方案內(nèi)置了客戶端,該客戶端封裝了支持web service服務(wù)調(diào)用的相關(guān)協(xié)議,因此測試人員不用在協(xié)議報文層面進行編碼,可以按照預(yù)先設(shè)定的方式執(zhí)行web service的服務(wù)調(diào)用,由本技術(shù)方案在后續(xù)步驟202中自動執(zhí)行這部分代碼的修改和編譯操作。在本實施例的一個具體例子中,測試人員提供的用Java編寫的測試代碼片段如下所示:
在上述例子提供的測試代碼片段中,測試人員按照預(yù)先設(shè)定的方式,直接采用被測服務(wù)名稱中的類名(未包含路徑部分)和被測方法名稱,完成了web service服務(wù)調(diào)用部分的代碼,即:credibleService.isCredible(),在后續(xù)步驟202中會對這部分代碼進行相應(yīng)的修改替換。在其他實施方式中,也可以預(yù)先設(shè)定其他的服務(wù)調(diào)用方式,只要測試人員按照該方式編寫服務(wù)調(diào)用代碼,本技術(shù)方案在步驟202中對采用該方式的服務(wù)調(diào)用代碼進行修改替換,就同樣可以實現(xiàn)本技術(shù)方案。
步驟202:在預(yù)處理階段,修改并編譯所述測試代碼,得到可執(zhí)行的測試代碼;所述修改是指將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象完成web service服務(wù)調(diào)用。
本步驟為執(zhí)行壓力測試之前的預(yù)處理階段,主要完成修改并編譯測試代碼的工作。由于本實施例是以JMeter插件的形式實現(xiàn)的,本步驟所述的預(yù)處理是指,在測試執(zhí)行之前通過前置處理器完成相關(guān)的準備工作,因此本階段也稱為前置處理階段。在本階段執(zhí)行如下所述的步驟202-1至步驟202-5,下面結(jié)合附圖4作進一步的詳細說明。
步驟202-1:將所述測試代碼所使用的第三方j(luò)ar包加載到對應(yīng)的類加載器中。
由于測試人員提供的java測試代碼,可能需要引入第三方j(luò)ar包,這些jar包文件通常位于對應(yīng)的testplan文件夾下。在壓力測試執(zhí)行之前,可以將所有用到的第三方j(luò)ar都提前加載到對應(yīng)的類加載器(classloader)中。
在Java運行過程中動態(tài)加載jar包,通常可以使用java.net.URLClassLoader類加載器,該加載器可以通過指定路徑將對應(yīng)的jar包或者class文件加載到類空間。具體實施時,可以通過遍歷存放第三方j(luò)ar包的目錄,獲取所有需加載的第三方j(luò)ar包文件,然后通過URLClassLoader類提供的addURL()方法完成動態(tài)加載。
步驟202-2:根據(jù)所述被測web service的配置信息,初始化所述對應(yīng)于被測web service的客戶端和方法對象。
作為一種可行的實施方式,每個測試線程可以自己初始化對應(yīng)于被測web service的客戶端(簡稱web service客戶端)和方法對象,然后使用所述客戶端和方法對象作為入口參數(shù)、調(diào)用可執(zhí)行的測試代碼完成測試任務(wù)。
為了提高執(zhí)行效率,本實施例提供一種在前置處理階段初始化web service客戶端和方法對象的優(yōu)選實施方式,采用這種方式,在啟動多線程進行壓力測試時,每個線程就可以使用統(tǒng)一的靜態(tài)客戶端和靜態(tài)方法對象,從而有效避免每個線程都執(zhí)行同樣的初始化操作可能導(dǎo)致的性能瓶頸。
在步驟201中獲取了被測web service的配置信息,包括:被測服務(wù)名稱serviceName,被測方法名稱methodName和被測web service的URL信息wsUrl,本步驟使用上述信息初始化所述客戶端和方法對象。下面給出了初始化XFire客戶端的Java示例代碼:
Class<?>className=Class.forName(serviceName);
Service service=new ObjectServiceFactory().create(className);
XFireProxyFactory factory=new XFireProxyFactory(XFireFactory
.newInstance().getXFire());
Object wsService=factory.create(service,wsUrl);
通過上述代碼片段完成了XFire客戶端的初始化,還可以進一步按照如下Java示例代碼進行客戶端的超時設(shè)置,其中超時時間的具體值timeout可以從JMeter圖形用戶界面獲?。?/p>
Client client=Client.getInstance(wsService);
client.setProperty(CommonsHttpMessageSender.HTTP_TIMEOUT,timeout);
完成所述客戶端的初始化后,可以進一步通過Java的反射機制,根據(jù)被測方法名稱methodName,從所述客戶端中獲取對應(yīng)的方法對象method。從而在后續(xù)步驟203執(zhí)行測試時,每個線程就可以使用已初始化好的客戶端wsService和方法對象method作為入口參數(shù),調(diào)用可執(zhí)行的測試代碼完成測試任務(wù)。
步驟202-3:修改所述測試代碼,生成待編譯的java文件。
本步驟將已獲取的Java測試代碼修改為:根據(jù)入口參數(shù)完成服務(wù)調(diào)用,并生成對應(yīng)的Java文件。此外,本步驟進行的代碼修改還可以包括:對參數(shù)化變量的處理、對返回語句的替換、以及添加相應(yīng)的引用語句。該處理過程包括如下所示的步驟202-3-1至步驟202-3-4,下面結(jié)合附圖5逐一進行說明。
步驟202-3-1:增加import語句。
針對后續(xù)需要做的代碼修改,增加import引用語句。例如,后續(xù)進行測試代碼的修改時需要用到JDK提供的List和ArrayList數(shù)據(jù)結(jié)構(gòu)、以及XFire客戶端,那么在測試代碼的開始部分可以添加如下所示的import引入語句:
import org.codehaus.xfire.service.service;
import java.util.ArrayList;
import java.util.List;
步驟202-3-2:替換服務(wù)調(diào)用語句。
由于本技術(shù)方案內(nèi)置了web service客戶端,因此測試人員不需要在協(xié)議層面進行編碼,也不需要自己初始化客戶端,這些對于測試人員來說都是透明的,測試人員只需要在測試代碼中按照預(yù)先設(shè)定的方式直接進行服務(wù)調(diào)用即可。本步驟則在測試代碼中增加入口參數(shù):客戶端和方法對象,并將原來的服務(wù)調(diào)用語句替換為根據(jù)入口參數(shù)執(zhí)行服務(wù)調(diào)用,由于本實施例中的測試代碼是采用Java語言編寫的,因此服務(wù)調(diào)用部分的代碼采用了反射寫法。
仍以步驟201中提供的測試代碼片段為例,在該例子中,測試代碼按照預(yù)先設(shè)定的方式直接采用被測服務(wù)名稱的類名(未包含路徑部分)和被測方法名稱,進行web service服務(wù)調(diào)用,調(diào)用語句如下所示:
boolean ret=credibleService.isCredible(query);
本步驟主要進行兩方面的代碼修改,首先,通過正則匹配的方式定位測試 代碼中的runTest()語句行,并在括號中添加兩個入口參數(shù):method和service,其中service是用于進行服務(wù)調(diào)用的客戶端參數(shù),method是用于進行服務(wù)調(diào)用的方法對象參數(shù);然后,從已獲取的被測服務(wù)名稱serviceName中提取類名部分,利用所述類名和方法名稱,采用正則匹配的方式在測試代碼中定位符合預(yù)定方式的服務(wù)調(diào)用語句,并將該語句替換為使用入口參數(shù)進行服務(wù)調(diào)用的反射寫法。此外,為了在后續(xù)的步驟202-3-4中能夠?qū)⑷肟趨?shù)和服務(wù)調(diào)用結(jié)果都以對象的形式返回,可以將服務(wù)調(diào)用返回結(jié)果的類型替換為Object。
經(jīng)過修改,上述測試代碼片段中的runTest()語句行被替換為如下語句:
public Object runTest(Method method,Object service){
上述測試代碼片段中的服務(wù)調(diào)用語句被替換為如下形式:
Object ret=method.invoke(service,query);
步驟202-3-3:進行參數(shù)化變量的處理。
作為一種優(yōu)選實施方式,本實施例還實現(xiàn)了測試過程的參數(shù)化。
現(xiàn)有壓力測試基本上都是基于協(xié)議報文的(例如SOAP報文),通過截獲并回訪SOAP報文的方式進行壓力測試。采用這種方式,如果要實現(xiàn)測試過程的參數(shù)化,通常需要對協(xié)議報文逐一解析,明確獲悉參數(shù)會以何種形式被封裝在協(xié)議報文中,對于可以支持多種協(xié)議格式的web service來說,要通過上述方式在SOAP報文中實現(xiàn)參數(shù)化,通常難度很大。而本技術(shù)方案由于內(nèi)置了客戶端,并且采用動態(tài)修改、編譯測試代碼的方式,因此為測試過程的參數(shù)化提供了便利。
由于本實施例以JMeter插件的形式實施,而JMeter自帶配置元件用于提供對靜態(tài)數(shù)據(jù)配置的支持,其中的CSV Data Set config組件(以下簡稱CSV組件)可以從本地數(shù)據(jù)文件中以行為單位讀入數(shù)據(jù)配置信息,然后根據(jù)預(yù)先指定的分隔符(例如逗號)分隔成若干個參數(shù)值,并用這些參數(shù)值替換測試代碼中的參數(shù)化變量部分,然后傳遞給某個線程。采用這種方式,每個線程都可以使用不同的參數(shù)值進行web service服務(wù)調(diào)用,使得壓力測試過程更為靈活。
使用CSV組件的上述功能,測試人員在編寫測試代碼時,可以將需要參數(shù)化的部分寫為CSV組件可識別的參數(shù)化變量的形式,例如,${userid}。
本實施例為了實現(xiàn)測試過程的參數(shù)化,將自定義參數(shù)以runTest()方法入口參數(shù)的形式傳入,并在每個線程開始執(zhí)行測試之前,獲取被CSV組件替換的具體 參數(shù)值、并用這些具體參數(shù)值作為入口參數(shù)調(diào)用可執(zhí)行的測試代碼(這部分請參見步驟203中的相關(guān)說明)。
具體到本步驟中,主要進行兩方面的代碼修改,首先通過正則匹配的方式定位測試代碼中的runTest()語句行,并在括號中添加所需的自定義參數(shù),在具體實施中,這部分處理可以與步驟202-3-2在入口參數(shù)中添加客戶端參數(shù)和方法對象參數(shù)的操作步驟合并處理;然后,根據(jù)參數(shù)化變量的形式${},通過正則匹配的方式定位測試代碼中的使用參數(shù)化變量的賦值語句,并用所述自定義參數(shù)替換賦值語句中的相應(yīng)參數(shù)化變量。
仍以步驟201中提供的測試代碼片段為例,在所述代碼片段中有兩個參數(shù)化變量${userid}和${ip},經(jīng)過上一步驟202-3-2和本步驟的修改,所述測試代碼片段中的runTest()語句行被替換為如下語句:
public Object runTest(Method method,Object service,String useridStr,String ipStr){
所述代碼片段中的兩行賦值語句被替換為如下形式:
String userid=useridStr;
String ip=ipStr;
步驟202-3-4:修改返回語句。
為了便于在測試完成之后進行問題定位與排查,本實施例還提供一種優(yōu)選實施方式:通過對測試代碼中的return語句的替換修改,使得測試代碼中的runTest()方法既可以返回執(zhí)行web service服務(wù)調(diào)用所采用的入口參數(shù)信息,也可以返回服務(wù)調(diào)用的結(jié)果信息。
具體說,本步驟可以通過正則匹配的方式定位測試代碼中的return語句,然后可以將該語句替換為實現(xiàn)如下功能的語句:在新定義的對象列表中依次添加各個入口參數(shù),并在所述對象列表中添加服務(wù)調(diào)用的返回結(jié)果,最后將所述對象列表作為runTest()方法的執(zhí)行結(jié)果返回。
至此,通過上述步驟202-3-1至步驟202-3-4,完成了對測試代碼的修改。在具體實施時,可以將修改后的測試代碼保存為.java文件,例如wsTest1.java,為后續(xù)步驟202-4進行動態(tài)編譯做好準備。
202-4:采用JDK提供的系統(tǒng)編譯器JavaCompiler編譯修改后的測試代碼。
本步驟編譯步驟202-3修改后生成的.java文件,從而得到可執(zhí)行的測試代碼。
在本實施例的一個具體例子中,采用JDK自帶的Java編譯器JavaCompiler完成本步驟的編譯操作。由于測試代碼中可能需要引入第三方j(luò)ar包,在上述步驟201中執(zhí)行了相應(yīng)的動態(tài)加載操作,在本步驟中為了避免編譯過程中出現(xiàn)錯誤,可以將步驟201中涉及的jar包所在目錄,添加到環(huán)境變量classpath中,并在編譯參數(shù)設(shè)置中通過“-cp”指定環(huán)境變量classpath。執(zhí)行本步驟的編譯操作后,將生成對應(yīng)的.class文件。
202-5:初始化可執(zhí)行對象。
在步驟202-4中編譯測試代碼后,得到了可執(zhí)行的測試代碼。作為一種可行的實施方式,可以在后續(xù)步驟203中由每個測試線程使用當前線程的類加載器將編譯生成的類加載至JVM,并通過反射機制實例化可執(zhí)行對象(包括:腳本對象實例和腳本方法對象),然后再通過調(diào)用可執(zhí)行對象完成本次測試任務(wù)。
為了提高執(zhí)行效率,本實施例提供一種在前置處理階段初始化可執(zhí)行對象的優(yōu)選實施方式,即,在前置處理階段完成步驟202-4的編譯操作后,直接將生成的.class文件顯示地加載到當前的類加載器中,并實例化可執(zhí)行對象。采用這種方式,在啟動多線程進行壓力測試時,每個線程就可以使用上述已初始化的統(tǒng)一的靜態(tài)可執(zhí)行對象,從而有效避免每個線程都執(zhí)行重復(fù)的加載和實例化操作可能導(dǎo)致的性能瓶頸。
在具體實施時,可以采用URLClassLoader類提供的loadClass()方法,將編譯后生成的.class文件顯示地加載到類加載器中,然后根據(jù)加載操作返回的類,通過newInstnce()方法獲取可執(zhí)行腳本對象的實例,然后再根據(jù)方法名"runTest"通過反射機制查詢得到具體的腳本方法對象。
步驟203:在測試執(zhí)行階段,每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
在測試執(zhí)行階段,可以并發(fā)初始化多個測試線程,在每個測試線程中調(diào)用步驟202編譯生成的可執(zhí)行測試代碼,從而完成測試任務(wù)。由于本實施例以JMeter插件的形式實施,因此測試人員可以在關(guān)于線程組的配置界面上設(shè)置并發(fā)線程數(shù)目等信息,初始化相應(yīng)數(shù)量測試線程的操作由JMeter自動完成。
其中,每個線程執(zhí)行的操作包括如下所示的步驟203-1至步驟203-3,下面結(jié)合附圖6作進一步說明。
步驟203-1:通過比對從所述圖形用戶界面獲取的測試代碼和由CSV組件 進行參數(shù)替換后的測試代碼,獲取參數(shù)化變量被替換后的具體值。
如上述步驟202-3-3中所述,作為一種優(yōu)選實施方式,本實施例為了實現(xiàn)測試過程的參數(shù)化,為測試代碼的runTest()方法添加了入口參數(shù),并對賦值語句中的參數(shù)化變量進行了替換。在測試線程初始化之前,即在執(zhí)行本步驟之前,JMeter的CSV組件針對每個測試線程,根據(jù)從本地數(shù)據(jù)文件中讀取的數(shù)據(jù)行,對測試代碼中的參數(shù)化變量進行了替換,因此每個測試線程在本步驟中可以獲取由CSV組件進行參數(shù)替換后的測試代碼,并通過與測試人員在JMeter圖形用戶界面中提供的測試代碼(以下簡稱原始測試代碼)的比對,獲取參數(shù)化變量被替換后的具體值。
具體說,由于在原始測試代碼中參數(shù)化變量通常采用${}形式,因此本步驟可以通過正則匹配的方式在原始測試代碼中定位包含參數(shù)化變量的代碼行,然后根據(jù)已定位的代碼行的位置信息,查找CSV替換后的測試代碼中的相應(yīng)代碼行,并截取參數(shù)化變量被替換后的具體取值。
仍以步驟201中提供的測試代碼片段為例,通過正則匹配定位到如下所示的兩個代碼行:
String userid=${userid};
String ip=${ip};
通過上述兩個代碼行的位置信息,在CSV替換后的測試代碼中找到如下所示的相應(yīng)代碼行:
String userid="1001";
String ip="192.168.1.1";
那么通過上述代碼行的比對,本步驟就可以從CSV替換后的測試代碼中截取參數(shù)化變量的具體參數(shù)值"1001"和"192.168.1.1",從而可以在后續(xù)的步驟203-2中使用具體的參數(shù)值作為入口參數(shù)進行web service的服務(wù)調(diào)用,從而實現(xiàn)測試過程的參數(shù)化,使得測試過程更為靈活。需要說明的是,上述例子中給出的變量以及具體參數(shù)值都僅僅是示意性的,在具體實施中,測試人員可以根據(jù)實際需要定義測試代碼中的變量、并且在供CSV讀取的本地數(shù)據(jù)文件中寫入所需的參數(shù)值。
步驟203-2:使用對應(yīng)于被測web service的客戶端、方法對象以及已獲取的具體參數(shù)值作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
在本實施例中,由于已經(jīng)在前置處理階段統(tǒng)一初始化了對應(yīng)于被測web service的客戶端和方法對象,因此本步驟中可以直接使用已初始化好的客戶端和方法對象作為入口參數(shù)。
由于本實施例還提供了測試過程參數(shù)化的優(yōu)選實施方式,在步驟202中進行了測試代碼的相應(yīng)修改,在步驟203-2中獲取了被CSV替換后的參數(shù)化變量的具體取值,因此在本步驟中,還可以將所述參數(shù)化變量的具體取值也作為入口參數(shù)的一部分。如果在其他實施方式中,不需要實現(xiàn)測試過程的參數(shù)化,那么就無需執(zhí)行上述與參數(shù)化相關(guān)的代碼修改操作、獲取參數(shù)化變量的具體取值的操作,在本步驟中也不需要在執(zhí)行服務(wù)調(diào)用的入口參數(shù)中添加相應(yīng)參數(shù)值。
在本實施例中,由于已經(jīng)在前置處理階段加載了編譯后的.class文件,并且統(tǒng)一初始化了可執(zhí)行對象,因此本步驟可以采用反射形式直接調(diào)用所述可執(zhí)行對象,完成本次的測試任務(wù)。以下為在本實施例的一個具體壓力測試例子中,測試線程調(diào)用可執(zhí)行對象的代碼片段:
results.sampleStart();
Object result=getScriptMethod().invoke(getScript(),paramProperties);
results.sampleEnd();
在上述代碼片段中,getScriptMethod()方法用于獲取已初始化的靜態(tài)的腳本方法對象,getScript()方法用于獲取已初始化的靜態(tài)的腳本對象實例,paramProperties是入口參數(shù)列表,其中包括:已初始化的web service客戶端和方法對象,以及在步驟203-1中獲取的具體的參數(shù)值。
步驟203-3:將所述調(diào)用操作返回的入口參數(shù)信息和結(jié)果信息,分別添加到JMeter結(jié)果樹的request屬性及response屬性中。
如前面步驟202-3-4所述,如果本實施例采用了在服務(wù)調(diào)用后將入口參數(shù)信息和結(jié)果信息一并返回的優(yōu)選實施方式,在步驟202-3-4中對測試代碼中的返回語句進行了相應(yīng)的修改,那么執(zhí)行服務(wù)調(diào)用操作后,本步驟就可以輸出返回的上述信息,例如,可以在圖形界面或者命令行窗口中顯示上述信息、或者將上述信息輸出到文件中,以便于進行問題的定位與排查。
由于本實施例是以JMeter插件的形式實施的,而JMeter為了便于測試人員根據(jù)測試結(jié)果進行問題的定位與排查,提供了多種查看測試結(jié)果的方法,例如:圖形報表、結(jié)果樹和聚合報告等。因此本步驟可以通過SampleResult類提供的setSamplerData()方法setResponseData()方法,將執(zhí)行服務(wù)調(diào)用返回的入口參數(shù)信息和結(jié)果信息分別添加到JMeter結(jié)果樹的request屬性和response屬性中,從 而在測試結(jié)束后,測試人員可以在JMeter結(jié)果樹界面的“請求”標簽頁面中查看入口參數(shù)信息,在“響應(yīng)數(shù)據(jù)”標簽頁面中查看調(diào)用結(jié)果信息,并在此基礎(chǔ)上進行進一步的問題定位與排查。
每個線程執(zhí)行上述步驟203-1至步驟203-3,用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
在每個線程完成自己的測試任務(wù)并退出后,可以在壓力測試的后置處理階段(例如,通過JMeter的后置處理器)完成與測試相關(guān)的收尾處理操作。如果在前置處理階段,修改在步驟201獲取的測試代碼并生成待編譯的java文件,例如wsTest1.java,并且通過編譯該文件生成了對應(yīng)的.class文件,例如wsTest1.class,鑒于壓力測試已經(jīng)結(jié)束,因此可以刪除上述臨時文件wsTest1.java和wsTest1.class文件,以避免臨時文件占用過多的存儲空間。
綜上所述,由于本技術(shù)方案內(nèi)置了支持web service服務(wù)調(diào)用相關(guān)協(xié)議的客戶端,因此提供測試代碼的測試人員無需了解網(wǎng)絡(luò)協(xié)議報文的細節(jié),也不用在協(xié)議報文層面進行編碼,直接按照預(yù)先設(shè)定的方式進行web service服務(wù)調(diào)用即可,從而不僅降低了測試人員的學(xué)習(xí)成本,而且簡化了編寫測試代碼的工作量,同時也為測試過程的參數(shù)化提供了一種簡便途徑。
在上述的實施例中,提供了一種web service壓力測試方法,與之相對應(yīng)的,本申請還提供一種web service壓力測試裝置。請參看圖7,其為本申請的一種web service壓力測試裝置的實施例示意圖。由于裝置實施例基本相似于方法實施例,所以描述得比較簡單,相關(guān)之處參見方法實施例的部分說明即可。下述描述的裝置實施例僅僅是示意性的。
本實施例的一種web service壓力測試裝置,包括:信息與代碼獲取單元701,用于獲取被測web service的配置信息、以及按照預(yù)先設(shè)定的方式執(zhí)行web service服務(wù)調(diào)用的測試代碼;測試預(yù)處理單元702,用于在預(yù)處理階段,修改并編譯所述測試代碼,得到可執(zhí)行的測試代碼;所述修改是指將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用,其中,所述客戶端封裝了支持web service服務(wù)調(diào)用的協(xié)議;測試執(zhí)行單元703,用于在測試執(zhí)行階段,每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
可選的,所述信息與代碼獲取單元獲取的被測web service的配置信息包 括:被測服務(wù)名稱、被測方法名稱、以及被測web service的URL信息。
可選的,所述測試預(yù)處理單元包括:
代碼修改子單元,用于修改所述測試代碼,所述修改是指將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用;
代碼編譯子單元,用于編譯修改后的測試代碼,得到可執(zhí)行的測試代碼;
所述測試預(yù)處理單元還包括:
客戶端初始化子單元,用于根據(jù)所述被測web service的配置信息,初始化所述對應(yīng)于被測web service的客戶端和方法對象;
相應(yīng)的,所述測試執(zhí)行單元具體用于,每個測試線程使用所述客戶端初始化子單元初始化的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù)。
可選的,所述裝置以JMeter插件的形式實現(xiàn);
相應(yīng)的所述信息與代碼獲取單元具體用于,通過JMeter的圖形用戶界面獲取所述被測web service的配置信息以及所述測試代碼。
可選的,所述代碼修改子單元除了包括:
服務(wù)調(diào)用修改子單元,用于將所述測試代碼修改為:根據(jù)入口參數(shù)提供的客戶端以及方法對象執(zhí)行web service服務(wù)調(diào)用;
所述代碼修改子單元還包括:
自定義參數(shù)修改子單元,用于在所述測試代碼的入口參數(shù)中添加測試所需的自定義參數(shù);
參數(shù)化變量替換子單元,用于用所述自定義參數(shù)替換所述測試代碼中的相應(yīng)參數(shù)化變量;
相應(yīng)的,所述測試執(zhí)行單元除了包括:
服務(wù)調(diào)用子單元,用于每個測試線程使用對應(yīng)于被測web service的客戶端和方法對象作為入口參數(shù),調(diào)用所述可執(zhí)行的測試代碼完成測試任務(wù);
所述測試執(zhí)行單元還包括:
參數(shù)值獲取子單元,用于在觸發(fā)所述服務(wù)調(diào)用子單元之前,每個測試線程通過比對從所述圖形用戶界面獲取的測試代碼和由CSV組件進行參數(shù)替換后的測試代碼,獲取參數(shù)化變量被替換后的具體值;
相應(yīng)的,所述測試執(zhí)行單元所使用的入口參數(shù)還包括,所述參數(shù)值獲取子單元獲取的參數(shù)化變量被替換后的具體值。
可選的,所述測試執(zhí)行單元是通過反射方式完成web service服務(wù)調(diào)用的。
可選的,所述測試預(yù)處理單元還包括:
jar包加載子單元,用于在觸發(fā)所述代碼修改子單元之前,將所述測試代碼所使用的第三方j(luò)ar包加載到對應(yīng)的類加載器中。
可選的,所述代碼修改子單元還包括:
返回語句修改子單元,用于修改所述測試代碼的返回語句,使其返回信息包括:執(zhí)行web service服務(wù)調(diào)用的入口參數(shù)信息、以及結(jié)果信息。
可選的,所述測試執(zhí)行單元還包括:
返回信息處理子單元,用于將所述調(diào)用操作返回的入口參數(shù)信息和結(jié)果信息,分別添加到JMeter結(jié)果樹的request屬性及response屬性中。
可選的,所述測試預(yù)處理單元還包括:
類加載子單元,用于將所述代碼編譯子單元生成的.class文件顯示的加載至對應(yīng)的類加載器中;
可執(zhí)行對象初始化子單元,用于根據(jù)所述類加載子單元執(zhí)行加載操作返回的類,通過反射機制初始化可執(zhí)行對象;
相應(yīng)的,所述測試執(zhí)行單元具體用于,每個測試線程調(diào)用所述已初始化的可執(zhí)行對象,完成測試任務(wù)。
本申請雖然以較佳實施例公開如上,但其并不是用來限定本申請,任何本領(lǐng)域技術(shù)人員在不脫離本申請的精神和范圍內(nèi),都可以做出可能的變動和修改,因此本申請的保護范圍應(yīng)當以本申請權(quán)利要求所界定的范圍為準。
在一個典型的配置中,計算設(shè)備包括一個或多個處理器(CPU)、輸入/輸出接口、網(wǎng)絡(luò)接口和內(nèi)存。
內(nèi)存可能包括計算機可讀介質(zhì)中的非永久性存儲器,隨機存取存儲器(RAM)和/或非易失性內(nèi)存等形式,如只讀存儲器(ROM)或閃存(flash RAM)。內(nèi)存是計算機可讀介質(zhì)的示例。
1、計算機可讀介質(zhì)包括永久性和非永久性、可移動和非可移動媒體可以由 任何方法或技術(shù)來實現(xiàn)信息存儲。信息可以是計算機可讀指令、數(shù)據(jù)結(jié)構(gòu)、程序的模塊或其他數(shù)據(jù)。計算機的存儲介質(zhì)的例子包括,但不限于相變內(nèi)存(PRAM)、靜態(tài)隨機存取存儲器(SRAM)、動態(tài)隨機存取存儲器(DRAM)、其他類型的隨機存取存儲器(RAM)、只讀存儲器(ROM)、電可擦除可編程只讀存儲器(EEPROM)、快閃記憶體或其他內(nèi)存技術(shù)、只讀光盤只讀存儲器(CD-ROM)、數(shù)字多功能光盤(DVD)或其他光學(xué)存儲、磁盒式磁帶,磁帶磁磁盤存儲或其他磁性存儲設(shè)備或任何其他非傳輸介質(zhì),可用于存儲可以被計算設(shè)備訪問的信息。按照本文中的界定,計算機可讀介質(zhì)不包括非暫存電腦可讀媒體(transitory media),如調(diào)制的數(shù)據(jù)信號和載波。
2、本領(lǐng)域技術(shù)人員應(yīng)明白,本申請的實施例可提供為方法、系統(tǒng)或計算機程序產(chǎn)品。因此,本申請可采用完全硬件實施例、完全軟件實施例或結(jié)合軟件和硬件方面的實施例的形式。而且,本申請可采用在一個或多個其中包含有計算機可用程序代碼的計算機可用存儲介質(zhì)(包括但不限于磁盤存儲器、CD-ROM、光學(xué)存儲器等)上實施的計算機程序產(chǎn)品的形式。