當(dāng)你預(yù)期的那一天,也許是你害怕的那一天,終于來(lái)到了:從工程師的隊(duì)伍里,你被提拔到了軟件項(xiàng)目領(lǐng)導(dǎo)或者團(tuán)隊(duì)領(lǐng)導(dǎo)即
項(xiàng)目經(jīng)理的位置。
這也許就是你選擇的職業(yè)道路,或許你不太情愿,將就嘗試一下。無(wú)論在哪種情況下,你都可能缺少工程學(xué)科、人員管理以及領(lǐng)導(dǎo)能力的相關(guān)教育。這需要更多的領(lǐng)導(dǎo)能力和管理(它們不是一回事),而不能象Dilbert(譯注:著名IT漫畫主角)那樣簡(jiǎn)單地和老板對(duì)抗了。
當(dāng)你考慮新的目標(biāo)時(shí),請(qǐng)考慮下面的活動(dòng)計(jì)劃列表。一次就抓住了每個(gè)亮點(diǎn),這是不可能的。但是這份建議說(shuō)明可以幫助你將注意力放在可以提高你和你的團(tuán)隊(duì)績(jī)效的活動(dòng)上。
一、建立優(yōu)先級(jí)
作為項(xiàng)目經(jīng)理,首先要做的、最重要的事是你需要有意識(shí)地建立優(yōu)先級(jí)。當(dāng)你仍陷于繁重的
軟件開發(fā)活動(dòng)中時(shí),你需要一套新的職責(zé)。過多的經(jīng)理新手不能抗拒技術(shù)的吸引而陷于此類活動(dòng),這將導(dǎo)致項(xiàng)目組的其他人員想要獲得經(jīng)理的幫助時(shí),卻得不到幫助。
有成效的領(lǐng)導(dǎo)知道他們首要的任務(wù)是為其他組員提供服務(wù)。這些服務(wù)包括訓(xùn)練和指導(dǎo)、解決問題和沖突、提供資源、建立項(xiàng)目目標(biāo)和優(yōu)先級(jí)、提供適當(dāng)?shù)募夹g(shù)指引。
要使每個(gè)組員都能清楚的知道,你總是可以幫助他們。我發(fā)現(xiàn)將自己定位于為被我監(jiān)督的人
工作是非常有意義的,而不是相反的。在你所作的事情中,對(duì)于組員要求你幫助他們這件事,應(yīng)該具有非屏蔽中斷的優(yōu)先級(jí)。
第二重要的,是使你的客戶滿意。作為一名經(jīng)理,沒有直接的能力使客戶滿意,因?yàn)槟阋巡辉偈亲鳛閭€(gè)人提供產(chǎn)品和服務(wù)完成這點(diǎn)。相反,你必須建立一種環(huán)境,準(zhǔn)許你的組員最大程度上滿足客戶的需求。經(jīng)理提供了強(qiáng)有力的方法,有效地提高客戶的滿意度。
第三重要的,是為你的項(xiàng)目工作。因?yàn)橐苍S還有其他許多技術(shù)上的項(xiàng)目,或者其他經(jīng)理的請(qǐng)求幫助,諸如為指導(dǎo)委員會(huì)工作。當(dāng)這些和二個(gè)高級(jí)別的發(fā)生沖突時(shí),都要準(zhǔn)備推辭掉。很明顯,使其他經(jīng)理滿意的事情是你最不重要的事情。
在一個(gè)有秩序的組織里,如果你在三個(gè)以上的重大環(huán)節(jié)上獲得了成功,其他的經(jīng)理都會(huì)很激動(dòng)的。我們并不都能很幸運(yùn)地工作在一個(gè)良好的環(huán)境里,但一定要對(duì)你任務(wù)單上排在最前面的工作任務(wù)努力盡到最大的責(zé)任。集中精力有效地、快樂地、盡可能地幫助你的組員,不要將精力放在使你上司滿意的上面。
二、分析你的技能差距
除非你已經(jīng)為新位置做好了準(zhǔn)備,否則相對(duì)于你當(dāng)前的領(lǐng)導(dǎo)能力和管理技能,你會(huì)感到一些差距。出色的技術(shù)背景或許是你被選為領(lǐng)導(dǎo)角色的一個(gè)因素,但是你要想干得出色,你需要更多的技能。針對(duì)別人的評(píng)論和項(xiàng)目,真實(shí)地列出你的長(zhǎng)處和短處,然后減少差距。軟件人員并不以令人滿意的人際關(guān)系技能出名。你會(huì)希望增強(qiáng)處理人際關(guān)系的經(jīng)驗(yàn):解決沖突、說(shuō)服以及灌輸想法。你也不得不處理包括招聘、解雇、商談?dòng)?jì)劃表,以及在你的辦公室里評(píng)論某人業(yè)績(jī)使其傷心落淚等一些事務(wù)。
我發(fā)現(xiàn)從一堂傾聽技能課開始我的管理職業(yè)是非常好的。當(dāng)作為個(gè)體提議人,積極地將我們自己的技術(shù)議程提交小組時(shí),我們經(jīng)常對(duì)此感到非常愜意。有效的管理要求更多的合作和善于接受的人際關(guān)系方式。要花點(diǎn)時(shí)間
學(xué)習(xí)如何(何時(shí))巧妙地引導(dǎo)自己的自然判斷。傾聽技能課提供了一種交流機(jī)制,我已經(jīng)發(fā)現(xiàn)在許多場(chǎng)合下都很有用。
接著,到講臺(tái)的另一側(cè),提高你的演講能力。如果你真的不適應(yīng)公開場(chǎng)合的講話,學(xué)習(xí)戴爾.卡內(nèi)基的課會(huì)有幫助的。你會(huì)發(fā)覺,通過這樣的培訓(xùn)獲得的經(jīng)驗(yàn),以及獲得提高的交流能力,都可以幫助你更好地適應(yīng)將來(lái)的工作。
作為項(xiàng)目領(lǐng)導(dǎo),為了計(jì)劃和跟蹤項(xiàng)目, 以及當(dāng)需要項(xiàng)目回退而采取修正措施時(shí),你有責(zé)任調(diào)整其他人的工作。參加
項(xiàng)目管理的培訓(xùn)課,閱讀一些有關(guān)項(xiàng)目和風(fēng)險(xiǎn)管理的書籍和
文章。參加項(xiàng)目管理學(xué)會(huì),閱讀其月刊--PM Network。SEI的軟件能力成熟度模型對(duì)于軟件項(xiàng)目計(jì)劃和項(xiàng)目跟蹤提供了很多有用的建議。建立優(yōu)先級(jí)的能力、控制有效果的會(huì)議、清晰的交流,對(duì)于你,作為一名經(jīng)理的績(jī)效將會(huì)有實(shí)質(zhì)上的影響。
定義“質(zhì)量”
幾乎每個(gè)人都會(huì)認(rèn)真地對(duì)待質(zhì)量問題而且都希望生產(chǎn)出高質(zhì)量的產(chǎn)品。然而,對(duì)于軟件的質(zhì)量含義,沒有一個(gè)統(tǒng)一的定義。傳統(tǒng)上的軟件質(zhì)量觀點(diǎn)和“足夠好”的軟件觀點(diǎn)有著激烈的爭(zhēng)論。為了幫助小組走向成功,需要花一些時(shí)間和你的組員、客戶共同探討質(zhì)量的含義。 這兩種陣營(yíng)在思想上經(jīng)常不會(huì)有相同的定義,可以很容易的就不同目的開展工作。關(guān)注交付計(jì)劃的經(jīng)理對(duì)于想正常地檢查每行代碼的工程師會(huì)不耐煩的;認(rèn)為可靠性非常重要的客戶對(duì)一個(gè)帶有很少使用但帶有很多bugs的特性的產(chǎn)品是不會(huì)滿意的;一個(gè)很好的GUI也許會(huì)讓用戶厭煩,因?yàn)橛脩粢呀?jīng)熟記了如何有效地使用前一個(gè)版本的產(chǎn)品。
為了更好的理解客戶對(duì)軟件質(zhì)量的看法,在Kodak,我的小組曾經(jīng)邀請(qǐng)了我們的客戶和他們的經(jīng)理就這個(gè)議題在一個(gè)開放的論壇展開討論。這個(gè)論壇是很有意義的,那些使用我們產(chǎn)品的人有著自己的理解,通過討論,我們可以知道我們制定質(zhì)量的思路有哪些和他們是不相符的。明白了不同,就可以使你集中精力,照顧客戶的最大利益,而不是使開發(fā)人員獲得最大滿意。
軟件質(zhì)量的傳統(tǒng)描述包括要與說(shuō)明書一致,滿足客戶的需求,代碼和文檔沒有缺陷。“六個(gè)∑質(zhì)量” (six-sigma quality)這個(gè)流行詞,建立了一個(gè)非常高的尺度,用于監(jiān)測(cè)失敗的頻率和密度。但它不適用于如快速產(chǎn)品交付,可用性,充足的特性集,已支付價(jià)錢的交付意義這樣的質(zhì)量尺度,。對(duì)于我們生產(chǎn)和購(gòu)買的產(chǎn)品,我們總是熱衷于盡可能涵蓋所有的這些質(zhì)量特性,然而,妥協(xié)總是必須的。
在一個(gè)項(xiàng)目的需求階段,我們制定了包括十項(xiàng)質(zhì)量屬性的一個(gè)列表,如效率,協(xié)同性,正確性以及宜于學(xué)習(xí),我們認(rèn)為這對(duì)于用戶來(lái)說(shuō)是最重要的。我們請(qǐng)客戶關(guān)鍵人物代表小組以1到5的尺度評(píng)估每項(xiàng)屬性。一旦我們決定了哪些屬性是最重要的,我們就可以設(shè)計(jì)并實(shí)現(xiàn)這些目標(biāo)。如果你在了解了對(duì)于客戶的質(zhì)量含義并在設(shè)計(jì)實(shí)現(xiàn)質(zhì)量屬性的過程中沒有麻煩的話,而且客戶對(duì)質(zhì)量屬性表示滿意,那你是很幸運(yùn)的。在眾多關(guān)注的質(zhì)量說(shuō)明中,我曾聽到過一個(gè):“客戶回來(lái)了,但產(chǎn)品沒有” 。和你的客戶、開發(fā)人員一起對(duì)每一個(gè)產(chǎn)品都確定適當(dāng)?shù)馁|(zhì)量目標(biāo)。一旦決定了,就給出達(dá)到質(zhì)量目標(biāo)的明確的最高優(yōu)先級(jí)。以身作則,按很高的質(zhì)量標(biāo)準(zhǔn)要求你自己的工作。采用這個(gè)座右銘:“力求盡善盡美,滿足于優(yōu)秀。”
三、表彰成績(jī)
對(duì)你組員成績(jī)的表彰和獎(jiǎng)勵(lì),是激勵(lì)他們的一種很重要的手段。除非你的小組中已經(jīng)有了一種表彰程序,否則這應(yīng)是你最重要的事情之一。表彰包括象征性的東西(證書,旅游獎(jiǎng)勵(lì))以及實(shí)際的東西(電影票,餐館禮品券,兌現(xiàn)獎(jiǎng))。在送贈(zèng)品時(shí)要說(shuō)一些親切的話語(yǔ):“感謝你所給予的幫助”或者“祝賀取得了成績(jī)”。在表彰和獎(jiǎng)勵(lì)上花費(fèi)很少的心思和錢,就可以獲得很多的友好和將來(lái)的合作。包括客戶代表,以及為項(xiàng)目成功做出過貢獻(xiàn)的支持人員等等開發(fā)組外的人員也可以獲得表彰。
和你的組員討論,了解他們
感興趣的表彰和獎(jiǎng)勵(lì)的方式。使得無(wú)論大小成就的表彰活動(dòng)成為小組文化的一個(gè)標(biāo)準(zhǔn)組成部分。對(duì)每位組員對(duì)其所作的工作表現(xiàn)出發(fā)自內(nèi)心的興趣也要給與含蓄的表?yè)P(yáng),為消除所有影響他們戰(zhàn)斗力的障礙盡你的力量。表彰是展示組員以及小組外的其他人的一種方式――你要知道并感謝他們?yōu)樾〗M成功所作的貢獻(xiàn)。
四、學(xué)習(xí)過去
你的小組在過去承擔(dān)的一些項(xiàng)目有可能沒有取得完全的成功。甚至在成功的項(xiàng)目上,我們也能經(jīng)常認(rèn)為一些事情我們下次會(huì)作得更好。當(dāng)你進(jìn)入了新的領(lǐng)導(dǎo)角色,需要花點(diǎn)時(shí)間了解早期的項(xiàng)目為什么失敗,并要計(jì)劃避免犯同樣的錯(cuò)誤。對(duì)于軟件開發(fā),每位經(jīng)理花時(shí)間處理每種可能要發(fā)生的錯(cuò)誤是非常困難的,學(xué)習(xí)過去的成功和失敗就是個(gè)成功的開始。
可以從過去你們小組承擔(dān)的一個(gè)沒有經(jīng)過檢查評(píng)估的項(xiàng)目著手,不要管其成功還是失敗,實(shí)施項(xiàng)目后的回顧(有時(shí)稱作事后調(diào)查分析)。你的目標(biāo)不是判定責(zé)任,而是為了在將來(lái)項(xiàng)目中作得更好。借此,可以了解什么已經(jīng)作得很好,什么應(yīng)該作得更好。在當(dāng)前每個(gè)項(xiàng)目的主要里程碑時(shí),通過集體討論或公平的組織者,用同樣的方式,領(lǐng)導(dǎo)小組用頭腦風(fēng)暴的方式對(duì)其展開分析。
另外,要了解領(lǐng)悟已有的軟件工業(yè)的最佳準(zhǔn)則。一個(gè)好的起點(diǎn)是Steve McConnell的Jolt Award獲獎(jiǎng)作品:快速開發(fā)(Rapid Development,Microsoft Press, 1996)的第三部分,敘述了27個(gè)最佳準(zhǔn)則。也要避免McConnell敘述的36個(gè)常見的軟件開發(fā)錯(cuò)誤。你的組員也許反對(duì)新的工作方式,但是你的角色是作為一名領(lǐng)導(dǎo),要確保團(tuán)隊(duì)一致連續(xù)地使用最佳可用的方法、過程和工具。積極促進(jìn)組員之間的信息共享,這樣局部單個(gè)最好的實(shí)踐經(jīng)驗(yàn)就能成為每個(gè)開發(fā)人員的工具箱的一部分。
五、建立改進(jìn)目標(biāo)
一旦你對(duì)過去的項(xiàng)目建立起了回顧,確立了質(zhì)量對(duì)小組的意義,你就要建立短期以及長(zhǎng)期改進(jìn)的一些目標(biāo)。目標(biāo)要盡可能量化,所以你要?jiǎng)澐謳讉€(gè)簡(jiǎn)單的階段,標(biāo)明你是否采取了適當(dāng)?shù)倪^程朝著目標(biāo)前進(jìn)。
例如,如果你認(rèn)定由于需求的不穩(wěn)定導(dǎo)致項(xiàng)目經(jīng)常延期,你可以建立一個(gè)改進(jìn)需求穩(wěn)定的目標(biāo),在6個(gè)月內(nèi)提高50%。這樣一個(gè)目標(biāo)需要你確切知道每周或每月需求的變化數(shù),清楚他們的出處,采取行動(dòng)控制那些變更。這可能要求你要改變與那些提交需求改變的人的交流方式。
你的目標(biāo)和階段是軟件過程改進(jìn)程序的組成部分,你要使之有序。作為缺乏創(chuàng)造力的官僚主義的最后避難所,輕視“過程”很流行。雖然事實(shí)上,每個(gè)小組都能找到改進(jìn)其工作的方式。當(dāng)然,如果你總是用已有的工作方式工作,你也就不要期望你會(huì)得到比以前更好的結(jié)果。有兩個(gè)強(qiáng)烈的原因要求改進(jìn)過程:校正問題,防止問題。確保你的改進(jìn)努力要圍繞著已知的或可預(yù)知的可能威脅項(xiàng)目成功的問題。領(lǐng)導(dǎo)你的小組找出當(dāng)前正在使用的方法的長(zhǎng)處和短處,以及項(xiàng)目面臨的風(fēng)險(xiǎn)。
我的小組召開了一次“兩段式頭腦風(fēng)暴”練習(xí),來(lái)確定改進(jìn)軟件生產(chǎn)力和質(zhì)量過程的絆腳石。在第一次會(huì)議中,參會(huì)者在便條上寫出他們關(guān)于會(huì)議主題的想法,一個(gè)便條一個(gè)想法。組織者將他們寫在便條上的想法收集上來(lái)并分組。最后,我們就會(huì)得到一打主要的分類,并將其記錄到活動(dòng)掛圖上。
第二次會(huì)議,相同的參會(huì)者在便箋上寫出解決這些障礙的思路,并貼在掛圖的合適位置。進(jìn)一步細(xì)化,歸納出一些詳細(xì)的活動(dòng),就可以成為我們努力的一部分,清除障礙,幫助組員實(shí)現(xiàn)軟件的質(zhì)量和生產(chǎn)力的目標(biāo)。
建立可度量和可達(dá)到的目標(biāo),便于你集中精力實(shí)現(xiàn)改進(jìn)。要使目標(biāo)具有明顯的優(yōu)先級(jí),并可周期性地監(jiān)視過程。記住你的目的是,提高你的項(xiàng)目和公司完成的技術(shù)和業(yè)務(wù)上成功,不要滿足于一些過程改進(jìn)書籍里提到的期望細(xì)節(jié)。要把改進(jìn)的工作視為迷你項(xiàng)目,具有可分發(fā)、資源、計(jì)劃和有責(zé)任的小項(xiàng)目。否則,過程改進(jìn)活動(dòng)將總處于比誘人的技術(shù)工作低的優(yōu)先級(jí)上。
六、緩慢的開始
這篇文章提供了許多建議,幫助你,一位軟件經(jīng)理新人,帶領(lǐng)你的小組走向偉大的成功。在日復(fù)一日新的工作壓力面前,要努力保持你的頭腦清醒。
在長(zhǎng)時(shí)間的塑造軟件開發(fā)小組的文化和習(xí)慣上,你還是個(gè)非常重要的角色。你不必一次性都作完,可以選擇跟環(huán)境最相關(guān)的的幾個(gè)開始。作為軟件經(jīng)理,除了項(xiàng)目要按時(shí)按照預(yù)算完成外,你要擔(dān)負(fù)的責(zé)任還很多。你還要:領(lǐng)導(dǎo)技術(shù)人員,將他們形成一個(gè)具有凝聚力的團(tuán)隊(duì);建立協(xié)同團(tuán)隊(duì)工作的環(huán)境;鼓勵(lì)和獎(jiǎng)賞高級(jí)軟件工程師的實(shí)踐應(yīng)用;平衡來(lái)自客戶、公司,組員和你自己的需求。
ava中的邏輯運(yùn)算符包括邏輯與&,邏輯或|,邏輯非!邏輯異或^,除此之外還有幾個(gè)比較相似的&&短路與,||短路或。
那么這幾個(gè)邏輯運(yùn)算符到底有什么意思呢?下面我們來(lái)看看
首先看邏輯與&的用法,只有兩個(gè)都為真,結(jié)果為真,如果看如下代碼
int a = 20;
int b = 5;
if(a>10&b>10){
System.out.println("true");
}else{
System.out.println("false");
}
輸出false
同樣|,只要有一個(gè)為真就是真
if(a>10|b>10){
System.out.println("true");
}else{
System.out.println("false");
}
輸出true
!的作用是取反
boolean a = true;
if(!a){
System.out.println("true");
}
接下來(lái)再看看短路與&&和短路或||
int a = 10;int b = 20;
if(a>10&&b++>10){
System.out.println(true)
}
System.out.println(b);
看看b的值是多少呢,這個(gè)時(shí)候很多人會(huì)答錯(cuò),b的值最終還是20
在這里由于第一個(gè)a>10為false,所以這個(gè)表達(dá)式為false,這樣就不會(huì)執(zhí)行后面的b++操作了,相當(dāng)于把b++給短路了,所以叫短路與。同樣短路或的作用是如果第一個(gè)為真,那么整個(gè)表達(dá)就為true,就把第二個(gè)表達(dá)式短路了。所以叫短路或。
把今天早上我在物聯(lián)網(wǎng)研究院參與的作業(yè)寶產(chǎn)品需求確認(rèn)的過程大致敘述一下,為將來(lái)即將走上
軟件開發(fā)工作崗位的同學(xué)揭開
項(xiàng)目管理的神秘面紗。
先說(shuō)說(shuō)項(xiàng)目背景吧。因?yàn)椋撥浖a(chǎn)品還沒有上線,涉及到商業(yè)機(jī)密,所以我只能大致說(shuō)明一下,這是一款智能
手機(jī)上的本地程序,中小學(xué)生可以在手機(jī)上提交作業(yè),教師在后臺(tái)評(píng)判作業(yè),學(xué)生可以瀏覽作業(yè)的評(píng)判結(jié)果。
項(xiàng)目組采用的項(xiàng)目管理方法論主要是基于scrum敏捷開發(fā),迭代或沖刺的周期為兩周。因?yàn)橐恍┛陀^原因,項(xiàng)目的某些方面沒有完全嚴(yán)格按照scrum來(lái)實(shí)施,例如:我們這里沒有明確誰(shuí)是PO和SM,當(dāng)然這種情況一般老板就是PO和SM,項(xiàng)目畢竟總要有人負(fù)責(zé)嘛。
需求確認(rèn)是每個(gè)迭代前的重要項(xiàng)目管理活動(dòng),今天早上主要做了這件事情,下面就說(shuō)說(shuō)這個(gè)過程,至于項(xiàng)目管理的其他方面,以后工作中碰到了,再抽時(shí)間整理成文。
早上8點(diǎn)半產(chǎn)品組內(nèi)部進(jìn)行了v0.4版本的范圍確定,當(dāng)然功能點(diǎn)不是用story描述的,所以說(shuō)不是嚴(yán)格的scrum,基本上確認(rèn)的是一個(gè)功能清單。產(chǎn)品組內(nèi)部確認(rèn)完成后,9點(diǎn)產(chǎn)品組和開發(fā)組的負(fù)責(zé)人及工程師在會(huì)議室就v0.4版本中的功能清單逐條評(píng)審。評(píng)審的過程由產(chǎn)品組逐條講解功能,開發(fā)組的軟件工程師確認(rèn)每個(gè)功能技術(shù)實(shí)現(xiàn)的可行性和開發(fā)工期上的可行性。對(duì)v0.4功能范圍達(dá)成共識(shí)后,產(chǎn)品組會(huì)后細(xì)化v0.4中的每個(gè)功能項(xiàng),給出界面原型圖和功能描述,提交到redmine上。開發(fā)組組長(zhǎng)根據(jù)redmine上的功能描述,在redmine上創(chuàng)建相應(yīng)的開發(fā)任務(wù)指派到開發(fā)人員身上,一個(gè)沖刺就定義完成了,
測(cè)試組根據(jù)功能描述準(zhǔn)備相應(yīng)的測(cè)試案例。
今天被同事問到一個(gè)問題,問題描述如下:
一個(gè)
測(cè)試類,只有一個(gè)帶參構(gòu)造函數(shù)。在帶參構(gòu)造函數(shù)上加@Test,同時(shí)加@Parameters注解從
testng.xml中傳遞參數(shù)。為保證測(cè)試函數(shù)在帶參構(gòu)造函數(shù)之后執(zhí)行,所以測(cè)試方法前的@Test加了dependsOnMethods屬性,依賴于帶參構(gòu)造函數(shù)。
重現(xiàn)問題的示例代碼如下:
package com.ibm.testng.test; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class WebTest { private int stayTime; //Constructor with params @Test @Parameters({"stayTime"}) public WebTest(int stayTime) { System.out.println("Constructor with parameter!"); this.stayTime = stayTime; } @Test(dependsOnMethods="WebTest") public void stayOnServer() { System.out.println("The times staying on server: " + stayTime); } } |
輸出結(jié)果:
根據(jù)輸出結(jié)果可知,錯(cuò)誤原因是沒有找到stayOnServer()依賴的測(cè)試函數(shù)WebTest()。可能會(huì)疑問,不是有名稱為WebTest()的函數(shù)嗎,而且還用@Test注解了,為什么會(huì)提示找不到呢?
這個(gè)錯(cuò)誤,跟TestNG的執(zhí)行原理有關(guān)。TestNG啟動(dòng)之后,先調(diào)用構(gòu)造函數(shù)創(chuàng)建所有的測(cè)試實(shí)例,然后才進(jìn)行測(cè)試。因此,構(gòu)造函數(shù)與測(cè)試函數(shù)的執(zhí)行時(shí)機(jī)不一樣,構(gòu)造函數(shù)在所有測(cè)試方法之前先執(zhí)行,沒有必要再通過@Test的dependsOnMethods屬性使測(cè)試函數(shù)依賴于構(gòu)造函數(shù)。
. 構(gòu)造函數(shù)沒必要用@Test注解(注解了也不會(huì)報(bào)錯(cuò)),但是TestNG不會(huì)把它當(dāng)做測(cè)試函數(shù),它也不會(huì)和其他測(cè)試函數(shù)一起執(zhí)行。可能習(xí)慣性地認(rèn)為帶參構(gòu)造函數(shù)前的@Parameters一定要和@Test一起使用,其實(shí)不是這樣的,@Parameters可以放的位置有如下兩種情況:
1. 任何已經(jīng)被@Test,@Factory或者Configuration annotation(@BeforeXXX/@AfterXXX)注解的函數(shù)。
2. 測(cè)試類中至多一個(gè)構(gòu)造函數(shù)前面。TestNG會(huì)調(diào)用該構(gòu)造函數(shù)創(chuàng)建測(cè)試實(shí)例,并從testng.xml中獲得該構(gòu)造函數(shù)需要的參數(shù)。
可能你希望使用某個(gè)構(gòu)造函數(shù)來(lái)創(chuàng)建測(cè)試實(shí)例,但是TestNG會(huì)根據(jù)自己的規(guī)則選擇構(gòu)造函數(shù)。TestNG選擇構(gòu)造函數(shù)的規(guī)則:
1. 通常情況下,會(huì)選擇默認(rèn)無(wú)參構(gòu)造函數(shù)或者自己添加的無(wú)參構(gòu)造函數(shù)。
2. 如果有帶參構(gòu)造函數(shù),且被@Parameters注解,就會(huì)選擇該帶參構(gòu)造函數(shù)。
3. 如果同時(shí)有無(wú)參構(gòu)造函數(shù)和帶參構(gòu)造函數(shù),且?guī)?gòu)造函數(shù)沒有被@Parameters注解,選擇無(wú)參構(gòu)造函數(shù)。
4. 如果只有帶參構(gòu)造函數(shù),但是帶參構(gòu)造函數(shù)沒有被@Parameters注解,執(zhí)行測(cè)試函數(shù)時(shí)拋出org.testng.TestNGException。
對(duì)于帶參構(gòu)造函數(shù)的測(cè)試類,使用@Factory注解,不僅可以解決帶參構(gòu)造函數(shù)沒有被@Parameters注解而導(dǎo)致的org.testng.TestNGException,而且還可以充分發(fā)揮TestNG參數(shù)化測(cè)試的優(yōu)勢(shì)。以添加如下@Factory注解的代碼為例:
@Factory public static Object[] create() { System.out.println("Create test objects!"); List<WebTest> objectList = new ArrayList<WebTest>(); for(int i=1; i<4; i++) { objectList.add(new WebTest(i*10)); } return objectList.toArray(); } |
上面代碼會(huì)創(chuàng)建3個(gè)stayTime分別為10,20,30的測(cè)試實(shí)例。如果使用@Parameters注解,必須創(chuàng)建3個(gè)test分別將10,20,30從testng.xml傳入。因此,@Factory為帶參構(gòu)造函數(shù)的類創(chuàng)建一系列有規(guī)律的測(cè)試實(shí)例提供了便利。
首先
QTP要連接MySql 先確保機(jī)器上有MySql的數(shù)據(jù)源 沒有的話去網(wǎng)上下一個(gè)裝上把。
我這里用的是Mysql 5.1的數(shù)據(jù)源 ,裝完后,在桌面新建一個(gè)TXT文檔,然后修改后綴改為udl,就變成了數(shù)據(jù)鏈接這樣子

,打開它,你會(huì)發(fā)現(xiàn)《提供程序》內(nèi)就沒有Mysql這個(gè)名字的程序 ,但是在windows的管理工具數(shù)據(jù)源內(nèi)能找Mysql 5.1的名字也可以添加,后來(lái)找了好久才知道原來(lái)Mysql在數(shù)據(jù)鏈接內(nèi)是叫 Miceosoft OLE DB Provider for ODBC Drivers 這個(gè)名字。
現(xiàn)在找到了名字 接下來(lái)就是設(shè)置《連接》的屬性,數(shù)據(jù)源名稱可以隨意填寫,下面的用戶名和密碼就需要MySql的管理人員給權(quán)限。當(dāng)都設(shè)置好了,點(diǎn)擊
測(cè)試連接,顯示連接成功的話就是能正常啟動(dòng)了。
上面配置好了以后,我們用記事本的方式打開*.udl,里面有這些內(nèi)容 我們只需要復(fù)制紅線那部分,這部分為鏈接地址
好了,接下來(lái)就進(jìn)入編寫階段了
實(shí)現(xiàn)功能
1:讀取
數(shù)據(jù)庫(kù) USER_ 表內(nèi)的 SCREEN 和 SEREENNAME 這兩列下含有"test_"字符串的數(shù)據(jù),
2:循環(huán)寫入一個(gè)登陸界面,實(shí)現(xiàn)正確登陸
3:驗(yàn)證點(diǎn),登陸完畢后主界面會(huì)有一個(gè)對(duì)象內(nèi)顯示 Welcome test01! ,用描述性編程找到該對(duì)象獲取其中我所需要的屬性值進(jìn)行驗(yàn)證
Dim conn Dim name Dim suu Dim inn '檢查字段 SystemUtil.Run "http://192.168.0.233/web/guest/home" '這一段就是復(fù)制當(dāng)時(shí)記事本里的那一段語(yǔ)句 這段語(yǔ)句有個(gè)問題就是 自己要手動(dòng)往里添加用戶密碼噢 所以我再里面加了一個(gè)Password=1111 Mysql="Provider=MSDASQL.1;Persist Security Info=False;User ID=root;Password=1111;Data Source=sqltest" 'select screenName,screenName from user_ where screenName like 'test__'; '這段話表示說(shuō) 搜索數(shù)據(jù)庫(kù)內(nèi) USER_ 表內(nèi) screenName,screenName 這2個(gè)列里面所有包含 test 的數(shù)據(jù) sql="select screenName,greeting from user_ where screenName like 'test__';" Set conn=CreateObject("ADODB.CONNECTION") conn.Open Mysql If conn.State<>0 Then Reporter.ReportEvent micPass,"連接成功","連接成功" else Reporter.ReportEvent mimicFail,"連接失敗","連接失敗" End If Set res=CreateObject("ADODB.Recordset") res.Open sql,conn,1,1 '1,1表示只讀;1,3表示插入數(shù)據(jù);2,3表示修改數(shù)據(jù) res.MoveFirst'使游標(biāo)指向第一個(gè)記錄 sum="" 'res.EOF表示游標(biāo)到達(dá)最后一行 While Not res.EOF '讀取整個(gè)表內(nèi)的所有數(shù)據(jù) ' For i=0 to res.Fields.Count-1'str.Fields.Count表示字段個(gè)數(shù) ' sum=sum& res(i) & " " '把整個(gè)記錄顯示出來(lái) ' Next |
'獲取數(shù)據(jù)庫(kù)內(nèi) screenName 列的每一行數(shù)據(jù) sum=res("screenName") '截取字符串內(nèi) 從左到右4位字符 suu=Left(sum,4) If suu = "test" Then '檢查字段變量 inn=res("greeting") '錄制登陸過程 把賬號(hào)密碼做參數(shù)化 Browser("測(cè)試比對(duì)樣品 - 登錄").Page("測(cè)試比對(duì)樣品 - 登錄").WebEdit("_58_login").Set sum @@ hightlight id_;_Browser("測(cè)試比對(duì)樣品 - 登錄").Page("測(cè)試比對(duì)樣品 - 登錄").WebEdit(" 58 login")_;_script infofile_;_ZIP::ssf1.xml_;_ Browser("測(cè)試比對(duì)樣品 - 登錄").Page("測(cè)試比對(duì)樣品 - 登錄").WebEdit("_58_password").set"1111" @@ hightlight id_;_Browser("測(cè)試比對(duì)樣品 - 登錄").Page("測(cè)試比對(duì)樣品 - 登錄").WebEdit(" 58 password")_;_script infofile_;_ZIP::ssf2.xml_;_ Browser("測(cè)試比對(duì)樣品 - 登錄").Page("測(cè)試比對(duì)樣品 - 登錄").WebButton("登錄").Click '這里是使用SPY抓取獲取到對(duì)象屬性值,對(duì)該對(duì)象2個(gè)屬性進(jìn)行描述性編程 對(duì)象庫(kù)內(nèi)不要放入被描述的對(duì)象 ,然后使用 .GetROProperty方法獲取所需要對(duì)象屬性值 '這里抓取了2個(gè)對(duì)象進(jìn)行描述是應(yīng)為2個(gè)該對(duì)象使用1個(gè)對(duì)象進(jìn)行描述時(shí),界面上還有其他對(duì)象的屬性是一樣的,所以描述對(duì)象時(shí) 盡量抓取對(duì)象獨(dú)有的屬性,當(dāng)一個(gè)屬性描述找不到時(shí),就再增加一個(gè)屬性描述 nn=Browser("測(cè)試比對(duì)樣品 - 稿件管理").Page("測(cè)試比對(duì)樣品 - 稿件管理").WebElement("innertext:=Welcome "&sum&"!","html tag:=SPAN").GetROProperty("innerhtml") '設(shè)置檢查點(diǎn) If nn=inn Then print "nn="&nn&" inn="&inn Reporter.ReportEvent micPass,"檢查點(diǎn)","PASS" else Reporter.ReportEvent micFail,"檢查點(diǎn)","Ng" End If Browser("測(cè)試比對(duì)樣品 - 稿件管理").Page("測(cè)試比對(duì)樣品 - 稿件管理").Link("text:=退出").Click End If 'Print sum & vbCRLF'打印所有查詢的記錄 VBCRLF 換行語(yǔ)句 res.MoveNext'使游標(biāo)進(jìn)入下一個(gè) Wend @@ hightlight id_;_Browser("測(cè)試比對(duì)樣品 - 稿件管理").Page("測(cè)試比對(duì)樣品 - 稿件管理").Link("退出")_;_script infofile_;_ZIP::ssf6.xml_;_ |
報(bào)告顯示結(jié)果
如果不檢查,虛擬桌面基礎(chǔ)架構(gòu)(VDI)可能會(huì)顯著增加網(wǎng)絡(luò)壓力,從而直接影響應(yīng)用程序的性能及終端用戶的體驗(yàn)。但是,如何知道VDI是否獲得了足夠的網(wǎng)絡(luò)帶寬呢?以下方法可以確定VDI的網(wǎng)絡(luò)性能。
VDI應(yīng)用程序性能:對(duì)終端用戶體驗(yàn)執(zhí)行基準(zhǔn)測(cè)試 無(wú)論您的基準(zhǔn)測(cè)試軟件提供了何種統(tǒng)計(jì)信息,總體性能中最重要的一部分是終端用戶體驗(yàn)。終端用戶不關(guān)心您的VDI系統(tǒng),他們只要求系統(tǒng)比以前更好更快。
如果網(wǎng)絡(luò)流量過載,或者后臺(tái)VDI服務(wù)器過載,那么應(yīng)用程序性能就會(huì)下降,而終端用戶體驗(yàn)也會(huì)隨之變差。在一些極端情況中,用戶敲擊鍵盤到屏幕顯示字母的延遲時(shí)間可能會(huì)達(dá)到1至2秒鐘。
因此,量化終端用戶體驗(yàn)的最佳方法之一是對(duì)比VDI環(huán)境與獨(dú)立PC的應(yīng)用程序加載時(shí)間。例如,您可以對(duì)比兩個(gè)環(huán)境的MicrosoftWord啟動(dòng)時(shí)間。用戶可能不會(huì)注意到幾秒鐘的差別,但是相差5秒鐘以上,那么您就必須采取措施優(yōu)化基礎(chǔ)架構(gòu)性能。
您還可以通過執(zhí)行一些計(jì)算密集型任務(wù)來(lái)測(cè)試終端用戶體驗(yàn)。例如,如果財(cái)務(wù)部門定期執(zhí)行一個(gè)復(fù)雜報(bào)表,那么您可以比較它在虛擬桌面和在獨(dú)立PC上的任務(wù)執(zhí)行時(shí)間。
無(wú)論是否對(duì)終端用戶體驗(yàn)進(jìn)行基準(zhǔn)測(cè)試,都一定要考慮網(wǎng)絡(luò)負(fù)載和延遲的影響。在上午9:00上班時(shí)間執(zhí)行基準(zhǔn)測(cè)試,得到的性能數(shù)據(jù)肯定與半夜執(zhí)行的結(jié)果不同。在VDI網(wǎng)絡(luò)處于最高負(fù)載時(shí)執(zhí)行基準(zhǔn)測(cè)試,得到的測(cè)試結(jié)果肯定是最準(zhǔn)確的。
測(cè)定VDI性能的另一種方法是使用免費(fèi)工具LoginVSI。這個(gè)工具不僅能在部署VDI時(shí)建立基準(zhǔn),也能夠在其修改之后,測(cè)試它的效果。
VDI網(wǎng)絡(luò)問題:發(fā)現(xiàn)飽和征兆
VDI環(huán)境產(chǎn)生的流量會(huì)大于普通非VDI環(huán)境。但是,VDI相關(guān)協(xié)議比其他網(wǎng)絡(luò)協(xié)議的效率更高,所以一定要檢查網(wǎng)絡(luò)中是否出現(xiàn)的飽和征兆。有許多方法可以測(cè)試網(wǎng)絡(luò)飽和狀態(tài),選擇的方法取決于具體的基礎(chǔ)架構(gòu)。使用Ping測(cè)試VDI服務(wù)器的網(wǎng)卡是最簡(jiǎn)單的。雖然Ping一般是用于檢查丟包狀態(tài),但是這個(gè)工具也能反映響應(yīng)時(shí)間。Ping信息用于判斷網(wǎng)絡(luò)延遲時(shí)間。而Tracert也有相似的作用。
如果VDI服務(wù)器運(yùn)行的是
Windows系統(tǒng),那么可以使用性能監(jiān)視器查看每個(gè)網(wǎng)卡的進(jìn)出流量。然而,使用這種方法需要注意兩個(gè)問題。首先,由于數(shù)據(jù)包大小不一,因而發(fā)送和接收數(shù)據(jù)包的數(shù)量不重要。您需要關(guān)注的是發(fā)送和接收的字節(jié)數(shù)。其次,一定要記住,如果采集數(shù)據(jù)的頻率過密,性能監(jiān)視器可能會(huì)對(duì)系統(tǒng)性能產(chǎn)生負(fù)面影響。
SNMP是另一種測(cè)試網(wǎng)絡(luò)飽和狀態(tài)的方法。許多網(wǎng)絡(luò)交換機(jī)都內(nèi)置了SNMP監(jiān)控功能,可用于檢查網(wǎng)絡(luò)運(yùn)行性能。
無(wú)論使用哪一種方法檢查網(wǎng)絡(luò)的飽和狀態(tài),都有很多網(wǎng)絡(luò)路徑需要分析。首先檢查VDI客戶端與VDI前端服務(wù)器(一般為負(fù)載均衡器)之間的路徑。其次檢查VDI前端和VDI后端之間的鏈路。由于VDI基礎(chǔ)架構(gòu)的創(chuàng)建方式不同,這可能并不簡(jiǎn)單。最后要檢查的是宿主服務(wù)器與存儲(chǔ)架構(gòu)之間的鏈路。
根據(jù)遇到的問題,您可能需要對(duì)網(wǎng)絡(luò)流量進(jìn)行優(yōu)先級(jí)劃分,或者升級(jí)網(wǎng)絡(luò)負(fù)載均衡。此外,提高VDI服務(wù)器與存儲(chǔ)基礎(chǔ)架構(gòu)之間的網(wǎng)絡(luò)速度也可能會(huì)有所幫助。
代理模式(Proxy Pattern)
代理模式是常用的Java 設(shè)計(jì)模式,它的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類的對(duì)象與一個(gè)委托類的對(duì)象關(guān)聯(lián),代理類的對(duì)象本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的對(duì)象的相關(guān)方法,來(lái)提供特定的服務(wù)。
如下列子:
package proxy; interface Dao{ public void insert(); } class JdbcDao implements Dao{ public void insert(){ System.out.println("in jdbc insert"); } } class HibernateDao implements Dao{ public void insert(){ System.out.println("in hibernate insert"); } } class ProxyDao implements Dao{ private Dao dao; public ProxyDao(Dao dao){ this.dao=dao; } public void insert() { System.out.println("write log before invoke"); dao.insert(); System.out.println("write log after invoke"); } } public static void main(String[] args) { Dao jdbcDao =new JdbcDao(); Dao proxydao = new ProxyDao(jdbcDao); proxydao.insert(); } } |
運(yùn)行結(jié)果:
write log before invoke
in jdbc insert
write log after invoke
隨著Proxy的流行,Sun把它納入到JDK1.3實(shí)現(xiàn)了Java的動(dòng)態(tài)代理。動(dòng)態(tài)代理和普通的代理模式的區(qū)別,就是動(dòng)態(tài)代理中的代理類是由 java.lang.reflect.Proxy類在運(yùn)行期時(shí)根據(jù)接口定義,采用Java反射功能動(dòng)態(tài)生成的。和 java.lang.reflect.InvocationHandler結(jié)合,可以加強(qiáng)現(xiàn)有類的方法實(shí)現(xiàn)。如圖2,圖中的自定義Handler實(shí)現(xiàn) InvocationHandler接口,自定義Handler實(shí)例化時(shí),將實(shí)現(xiàn)類傳入自定義Handler對(duì)象。自定義Handler需要實(shí)現(xiàn) invoke方法,該方法可以使用Java反射調(diào)用實(shí)現(xiàn)類的實(shí)現(xiàn)的方法,同時(shí)當(dāng)然可以實(shí)現(xiàn)其他功能,例如在調(diào)用實(shí)現(xiàn)類方法前后加入Log。而Proxy類根據(jù)Handler和需要代理的接口動(dòng)態(tài)生成一個(gè)接口實(shí)現(xiàn)類的對(duì)象。當(dāng)用戶調(diào)用這個(gè)動(dòng)態(tài)生成的實(shí)現(xiàn)類時(shí),實(shí)際上是調(diào)用了自定義Handler的 invoke方法。
Proxy類提供了創(chuàng)建動(dòng)態(tài)代理類及其實(shí)例的靜態(tài)方法。
(1)getProxyClass()靜態(tài)方法負(fù)責(zé)創(chuàng)建動(dòng)態(tài)代理類,它的完整定義如下:
public static Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws IllegalArgumentException
參數(shù)loader 指定動(dòng)態(tài)代理類的類加載器,參數(shù)interfaces 指定動(dòng)態(tài)代理類需要實(shí)現(xiàn)的所有接口。
(2)newProxyInstance()靜態(tài)方法負(fù)責(zé)創(chuàng)建動(dòng)態(tài)代理類的實(shí)例,它的完整定義如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws
IllegalArgumentException
參數(shù)loader 指定動(dòng)態(tài)代理類的類加載器,參數(shù)interfaces 指定動(dòng)態(tài)代理類需要實(shí)現(xiàn)的所有接口,參數(shù)handler 指定與動(dòng)態(tài)代理類關(guān)聯(lián)的 InvocationHandler 對(duì)象。
以下兩種方式都創(chuàng)建了實(shí)現(xiàn)Foo接口的動(dòng)態(tài)代理類的實(shí)例:
/**** 方式一 ****/
//創(chuàng)建InvocationHandler對(duì)象
InvocationHandler handler = new MyInvocationHandler(...);
//創(chuàng)建動(dòng)態(tài)代理類
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
//創(chuàng)建動(dòng)態(tài)代理類的實(shí)例
Foo foo = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
/**** 方式二 ****/
//創(chuàng)建InvocationHandler對(duì)象
InvocationHandler handler = new MyInvocationHandler(...);
//直接創(chuàng)建動(dòng)態(tài)代理類的實(shí)例
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class }, handler);
由Proxy類的靜態(tài)方法創(chuàng)建的動(dòng)態(tài)代理類具有以下特點(diǎn):
動(dòng)態(tài)代理類是public、final和非抽象類型的;
動(dòng)態(tài)代理類繼承了java.lang.reflect.Proxy類;
動(dòng)態(tài)代理類的名字以“$Proxy”開頭;
動(dòng)態(tài)代理類實(shí)現(xiàn)getProxyClass()和newProxyInstance()方法中參數(shù)interfaces指定的所有接口;
Proxy 類的isProxyClass(Class<?> cl)靜態(tài)方法可用來(lái)判斷參數(shù)指定的類是否為動(dòng)態(tài)代理類。只有通過Proxy類創(chuàng)建的類才是動(dòng)態(tài)代理類;
動(dòng)態(tài)代理類都具有一個(gè)public 類型的構(gòu)造方法,該構(gòu)造方法有一個(gè)InvocationHandler 類型的參數(shù)。
由Proxy類的靜態(tài)方法創(chuàng)建的動(dòng)態(tài)代理類的實(shí)例具有以下特點(diǎn):
1. 假定變量foo 是一個(gè)動(dòng)態(tài)代理類的實(shí)例,并且這個(gè)動(dòng)態(tài)代理類實(shí)現(xiàn)了Foo 接口,那么“foo instanceof Foo”的值為true。把變量foo強(qiáng)制轉(zhuǎn)換為Foo類型是合法的:
(Foo) foo //合法
2.每個(gè)動(dòng)態(tài)代理類實(shí)例都和一個(gè)InvocationHandler 實(shí)例關(guān)聯(lián)。Proxy 類的getInvocationHandler(Object proxy)靜態(tài)方法返回與參數(shù)proxy指定的代理類實(shí)例所關(guān)聯(lián)的InvocationHandler 對(duì)象。
3.假定Foo接口有一個(gè)amethod()方法,那么當(dāng)程序調(diào)用動(dòng)態(tài)代理類實(shí)例foo的amethod()方法時(shí),該方法會(huì)調(diào)用與它關(guān)聯(lián)的InvocationHandler 對(duì)象的invoke()方法。
InvocationHandler 接口為方法調(diào)用接口,它聲明了負(fù)責(zé)調(diào)用任意一個(gè)方法的invoke()方法:
Object invoke(Object proxy,Method method,Object[] args) throws Throwable
參數(shù)proxy指定動(dòng)態(tài)代理類實(shí)例,參數(shù)method指定被調(diào)用的方法,參數(shù)args 指定向被調(diào)用方法傳遞的參數(shù),invoke()方法的返回值表示被調(diào)用方法的返回值。
最后看一個(gè)例子,該例子模仿spring 的AOP原理。
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; class Logic{ public void logic(){ Dao dao = Factory.create(); System.out.println("dynamic proxy's name: "+dao.getClass().getName()); dao.insert(); } } class Factory{ static Dao create(){ Dao dao = new JdbcDao(); MyInvocationHandler hand = new MyInvocationHandler(); return (Dao)hand.get(dao); } } interface Dao{ public void update(); public void insert(); } class JdbcDao implements Dao{ public void update(){ System.out.println("in jdbc update"); } public void insert(){ System.out.println("in jdbc insert"); } } class HibernateDao implements Dao{ public void update(){ System.out.println("in hibernate update"); } public void insert(){ System.out.println("in hibernate insert"); } } class MyInvocationHandler implements InvocationHandler { Object o; public Object get(Object o){ System.out.println("in get method of MyInvocationHandler"); this.o = o; return Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this); } public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { System.out.println("write log before invoke"); Object result = arg1.invoke(o, arg2); System.out.println("write log after invoke"); return result; } } public class Test { public static void main(String[] args) { Logic l = new Logic(); l.logic(); } } |
運(yùn)行結(jié)果:
in get method of MyInvocationHandler
dynamic proxy's name: proxy.$Proxy0
write log before invoke
in jdbc insert
write log after invoke
結(jié)論: JDK的動(dòng)態(tài)代理并不能隨心所欲的代理所有的類。Proxy.newProxyInstance方法的第二個(gè)參數(shù)只能是接口數(shù)組, 也就是Proxy只能代理接口。
Glass Box 是
IBM Security
AppScan Standard Edition(以下簡(jiǎn)稱 AppScan)8.5 版本以后引進(jìn)的一個(gè)新的組件,是對(duì) AppScan 的一個(gè)比較大的改進(jìn)。Glass Box 引進(jìn)了運(yùn)行時(shí)分析的技術(shù),通過部署在服務(wù)器端的代理,在探索和
測(cè)試階段搜集
Web 應(yīng)用程序信息,并進(jìn)行分析,進(jìn)而反饋給 AppScan,使 AppScan 更有針對(duì)性的進(jìn)行探索和掃描,提高了掃描的精確性,并有利于發(fā)現(xiàn)更多的漏洞。
Glass Box 并不僅僅是 AppScan 的一個(gè)新的特性,而是代表了一種全新的思想,將動(dòng)態(tài)分析技術(shù)與傳統(tǒng)的 AppScan
黑盒測(cè)試技術(shù)結(jié)合起來(lái),對(duì) Web 應(yīng)用程序進(jìn)行代碼級(jí)別的分析,給出更精確的分析結(jié)果,從而更有效的幫助客戶保護(hù)好自己的網(wǎng)站。
前言
Glass Box 是 IBM Security AppScan Standard Edition(以下簡(jiǎn)稱 AppScan)8.5 版本以后引進(jìn)的一個(gè)新的組件,是對(duì) AppScan 的一個(gè)比較大的改進(jìn)。Glass Box 引進(jìn)了運(yùn)行時(shí)分析的技術(shù),通過部署在服務(wù)器端的代理,在探索和測(cè)試階段搜集 Web 應(yīng)用程序信息,并進(jìn)行分析,進(jìn)而反饋給 AppScan,使 AppScan 更有針對(duì)性的進(jìn)行探索和掃描,提高了掃描的精確性,并有利于發(fā)現(xiàn)更多的漏洞。Glass Box 并不僅僅是 AppScan 的一個(gè)新的特性,而是代表了一種全新的思想,將動(dòng)態(tài)分析技術(shù)與傳統(tǒng)的 AppScan 黑盒測(cè)試技術(shù)結(jié)合起來(lái),對(duì) web 應(yīng)用程序進(jìn)行代碼級(jí)別的分析,給出更精確的分析結(jié)果,從而更有效的幫助客戶保護(hù)好自己的網(wǎng)站。
本文首先簡(jiǎn)單介紹了 AppScan Glass Box 的技術(shù)架構(gòu),然后介紹了在 AppScan 8.5 中 Glass Box 在
Windows XP 下使用效果。Glass Box 支持 WebSphere、Tomcat、JBoss 等多種應(yīng)用服務(wù)器,本文選擇的 Web 服務(wù)器為大家常見的 Tomcat 7.0。
技術(shù)架構(gòu)
Glass Box 可分為客戶端和服務(wù)端。客戶端又可分為 GlassAPI 和 Glass Box 引擎服務(wù),GlassAPI 用于和服務(wù)器端通信,獲取服務(wù)端返回的問題信息;Glass Box 引擎服務(wù)基于預(yù)定義的驗(yàn)證規(guī)則,對(duì)獲取到的服務(wù)端進(jìn)行分析,判斷是否存在漏洞。服務(wù)端通過代理程序搜集服務(wù)器端信息,包括 Web 應(yīng)用程序運(yùn)行時(shí)信息(根據(jù)預(yù)定義的特征匹配規(guī)則)、源代碼信息、配置文件信息、
操作系統(tǒng)信息、
數(shù)據(jù)庫(kù)信息和 Web 服務(wù)器信息等,并將搜集到的信息返回給客戶端。
圖 1. Glass Box 技術(shù)架構(gòu)圖
配置及使用
打開掃描配置面板,可對(duì) Glass Box 進(jìn)行配置。點(diǎn)擊 Glass Box 面板中的添加按鈕,可添加 Glass Box 代理程序。
圖 2. Glass Box 代理程序定義
代理程序的用戶名和密碼分別為安裝 Glass Box 時(shí)設(shè)定的用戶名和密碼,如需要修改密碼,可運(yùn)行 AgentCredentials.bat <username> <password> ,或直接修改位于 GBootStrap\WEB-INF 目錄下的 users.xml 文件,重啟 Tomcat 后生效。用戶可添加多個(gè) Glass Box 代理程序,但 AppScan 同一時(shí)間只能使用其中的一個(gè)。添加代理程序成功后,可對(duì) Glass Box 進(jìn)行設(shè)置,選中"在探索階段使用 glass box ",可發(fā)現(xiàn)更多的隱藏的 URL;選中"在測(cè)試階段使用 glass box",可發(fā)現(xiàn)更多的漏洞和提供更詳細(xì)的漏洞信息。配置成功后,AppScan 右下角狀態(tài)欄將顯示"Glass box 掃描:已啟用"。
Glass Box 配置成功后,需要對(duì) Web 應(yīng)用程序重新掃描。需要注意的是,由于 Glass Box 對(duì) URL 的解析問題,掃描本地網(wǎng)站需要配置虛擬域名,即起始 URL 不能是“http://localhost/myproject”, 而應(yīng)該是“http://mysite/myproject”。Glass Box 目前僅支持 Java 項(xiàng)目。本文所選用掃描網(wǎng)站是 IBM AppScan 開發(fā)人員提供的 AltoroJ 項(xiàng)目。
通過對(duì)配置 Glass Box 前后的掃描結(jié)果進(jìn)行分析,我們分析一下使用 Glass Box 的三個(gè)優(yōu)勢(shì)。為方便起見,本文采用默認(rèn)的掃描配置(新建一個(gè)常規(guī)掃描,采用默認(rèn)的掃描策略,對(duì)掃描配置的各項(xiàng)參數(shù)不做任何修改),并且沒有對(duì)結(jié)果進(jìn)行分析,排除誤報(bào)的漏洞。每次掃描,結(jié)果可能會(huì)略有不同;若差別太大,則應(yīng)該檢查掃描配置信息,查看日志,找出問題所在。
1. 在探索階段通過檢測(cè)出代碼中不可見的參數(shù)和 cookie 信息,探索隱藏的掃描路徑,提高掃描覆蓋率。
在應(yīng)用程序中,有一些參數(shù)并未暴露給用戶,即對(duì)用戶是"不可見"的,傳統(tǒng)的 AppScan 運(yùn)行在客戶端,并不能夠檢測(cè)到這些參數(shù),更無(wú)法探索到相關(guān)的頁(yè)面。 Glass Box 運(yùn)行于探索階段全過程,預(yù)定義一些"感興趣"的方法(如 getParameter、Runtime.getRuntime().exec 等),并時(shí)刻檢測(cè)這些方法是否運(yùn)行,并進(jìn)而探索出其中的參數(shù),再根據(jù)這個(gè)參數(shù)構(gòu)造掃描路徑。
2. 在測(cè)試階段,Glass Box 可增強(qiáng) AppScan 在各種漏洞類型方面的檢測(cè)。
Glass Box 通過搜集服務(wù)端信息,可減少誤報(bào)率,增強(qiáng) AppScan 對(duì)各種漏洞類型的檢測(cè),主要能夠增強(qiáng) AppScan 對(duì)注入攻擊、不安全的直接對(duì)象引用、安全配置錯(cuò)誤和不安全的加密存儲(chǔ)等漏洞的檢測(cè)。通過掃描 AltoroJ 項(xiàng)目可以發(fā)現(xiàn),配置 Glass Box 前,共掃描出了 100 個(gè)漏洞;而配置 Glass Box 后,共掃描到了 139 個(gè)漏洞;Glass Box 增加了了大約 40% 的漏洞掃描發(fā)現(xiàn)數(shù)量。下表是按照 OWASP Top 10 漏洞分類方法,對(duì)使用 Glass Box 前后的掃描漏洞數(shù)量進(jìn)行的對(duì)比。
表 1. 使用 Glass Box 前后發(fā)現(xiàn)的漏洞數(shù)量對(duì)比
有時(shí)候,Web 開發(fā)人員會(huì)屏蔽錯(cuò)誤信息,比如設(shè)置一個(gè)錯(cuò)誤頁(yè)面,發(fā)生異常時(shí)直接跳轉(zhuǎn)到該頁(yè)面,AppScan 無(wú)法直接從 response 信息中判斷是否存在漏洞。Glass Box 通過預(yù)定義的方法,搜集服務(wù)器端的信息,從而判斷是否存在漏洞。
通過掃描我們發(fā)現(xiàn),未使用 Glass Box 前,AppScan 并未檢測(cè)出用戶登錄頁(yè)面的
SQL 注入漏洞(AppScan 可檢測(cè)出各種類型的漏洞,未檢測(cè)出該頁(yè)面的 SQL 注入漏洞屬于個(gè)別情況)。我們來(lái)分析一下原因。
AppScan 在測(cè)試階段,向登陸頁(yè)面發(fā)送請(qǐng)求,我們假定 AppScan 將 Username 和 Password 均設(shè)置為"'",服務(wù)器返回錯(cuò)誤信息"Syntax error: Encountered "\'" at line 1, column 63. "。由于在 Response 中并未包含 SQL 異常信息,所以 AppScan 無(wú)法判斷是否存在 SQL 注入漏洞。
圖 3. 頁(yè)面顯示的錯(cuò)誤信息
但是如果我們寫一個(gè)測(cè)試代碼,可得知當(dāng)我們輸入單引號(hào)時(shí),服務(wù)器端確實(shí)報(bào)了 SQL 語(yǔ)法錯(cuò)誤信息,如圖 4 所示。Glass Box 安裝在服務(wù)器端,當(dāng)它發(fā)現(xiàn)請(qǐng)求值為 g'[number]b,且包含了單引號(hào)的信息請(qǐng)求時(shí),如果出現(xiàn) SQL 異常錯(cuò)誤信息,那么 Glass Box 便判斷出該頁(yè)面存在 SQL 注入漏洞。
圖 4.SQL 異常信息
3. 在生成報(bào)告階段,可提供代碼級(jí)的調(diào)試信息和修復(fù)建議
我們以 AltoroJ 項(xiàng)目的登陸頁(yè)面為例,對(duì)比一下使用黑盒測(cè)試和使用 Glass Box 發(fā)現(xiàn)的漏洞的修復(fù)過程。AppScan 通過分別在 Username 和 Password 輸入框中輸入"4ppSc4n"和"A' OR '7659'='7659",發(fā)現(xiàn)了該頁(yè)面存在 SQL 注入漏洞(AppScan 中稱之為"SQL 注入的認(rèn)證旁路")。我們根據(jù)"請(qǐng)求 / 響應(yīng)"信息可以發(fā)現(xiàn),該漏洞存在于 doLogin 這個(gè) servlet 中,如圖 5 所示。
圖 5.AppScan “請(qǐng)求 / 響應(yīng)”
我們根據(jù) WEB-IBF/web.xml 中的信息進(jìn)一步判斷出漏洞存在于 LoginServlet.java 文件中。
清單 1.web.xml 文件中的 LoginServlet 配置
<servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/doLogin</url-pattern> </servlet-mapping> <servlet> <description> </description> <display-name> LoginServlet</display-name> <servlet-name>LoginServlet</servlet-name> <servlet-class> com.ibm.rational.appscan.altoromutual.servlet.LoginServlet </servlet-class> </servlet> |
打開 LoginServlet.java 文件,我們依然很難一眼就判斷出漏洞的準(zhǔn)確位置,需要對(duì)代碼做進(jìn)一步的分析。經(jīng)過分析,找到存在漏洞的語(yǔ)句:
清單 2. LoginServlet.java 文件中存在漏洞的語(yǔ)句
if (!DBUtil.isValidUser(username, password))
然后,我們?cè)僬业?DBUtil 類中的 isValidUser 函數(shù),最終找到了存在漏洞的 sql 語(yǔ)句:
清單 3. 存在漏洞的 SQL 語(yǔ)句
ResultSet resultSet = statement.executeQuery("SELECT COUNT(*)FROM PEOPLE WHERE USER_ID
= '"+ user +"' AND PASSWORD='" + password + "'");
/* BAD - user input should always be sanitized */
雖然有時(shí)候?qū)τ诮?jīng)驗(yàn)豐富的開發(fā)者來(lái)說(shuō),對(duì)于邏輯簡(jiǎn)單程序能夠直接定位到某個(gè) java 文件,省去一些步驟,但是大部分情況下,我們都需要一步步的去分析。而對(duì)于 Glass Box 發(fā)現(xiàn)的漏洞,則可以大大節(jié)省開發(fā)人員定位代碼漏洞的時(shí)間。Glass Box 可報(bào)告出漏洞的具體位置信息,如方法名、類名、文件名和行號(hào)等信息;并可報(bào)告運(yùn)行時(shí)信息。如圖 6 所示。
圖 6. Glass Box 問題信息
總結(jié)
黑盒測(cè)試技術(shù)由于無(wú)法獲取應(yīng)用程序的內(nèi)部信息,導(dǎo)致掃描覆蓋率偏低,且無(wú)法提供詳細(xì)的調(diào)試信息;而白盒測(cè)試技術(shù)的代價(jià)過于高昂,需要大量的人工成本,且誤報(bào)率較高。而 Glass Box 是有別于傳統(tǒng)黑盒測(cè)試和白盒測(cè)試的一種混合測(cè)試技術(shù),將有效解決這一難題,為客戶創(chuàng)造更好的價(jià)值。
一、概述
Loadrunner擁有極為豐富的工具箱,供予我們制造出各種奇妙魔法的能力。其中就有此次要討論的socket套接字操作。
二、socket概述
socket是
操作系統(tǒng)中I/O系統(tǒng)的網(wǎng)絡(luò)延伸部分,它擴(kuò)展了操作系統(tǒng)的基本I/O到網(wǎng)絡(luò)通信,使進(jìn)程和機(jī)器之間的通信成為可能。如果想完全地理解socket在Loadrunner中如何
工作的,熟悉一些關(guān)于它的歷史會(huì)很有幫助。
當(dāng)前常用的socket,最早起源于BSD UNIX類的操作系統(tǒng)。在UNIX系統(tǒng)上,比如BSD,把對(duì)網(wǎng)絡(luò)的支持加入操作系統(tǒng),以一種擴(kuò)展現(xiàn)有文件描述符(后注)結(jié)構(gòu)的方法來(lái)實(shí)現(xiàn)的。Socket 可以被看成一個(gè)標(biāo)準(zhǔn)的文件描述符。在 UNIX 類的平臺(tái)上,其中包括open()、read()、write()和close()。很多時(shí)間,程序并不需要知道它正在把數(shù)據(jù)寫進(jìn)一個(gè)文件、終端、或是一個(gè)TCP連接。
系統(tǒng)調(diào)用被加入并和socket一起工作,而很多現(xiàn)有的系統(tǒng)調(diào)用同樣能和socket一起工作。因此,一個(gè)socket允許您使用標(biāo)準(zhǔn)的操作系統(tǒng)和其他的計(jì)算機(jī),以及您自己機(jī)器上的不同進(jìn)程來(lái)通信。
然而,socket的確存在一些不同工作方式。最明顯地就是建立socket的方法。很多文件是通過調(diào)用open()函數(shù)來(lái)打開的,但socket是通過調(diào)用socket()函數(shù)來(lái)建立的,并且還需要另外的調(diào)用來(lái)連接和激活他們。recv()和send()這兩個(gè)系統(tǒng)調(diào)用和read()和write()極為相似。
Socket是一套建立在TCP/IP協(xié)議上的接口不是一個(gè)協(xié)議,只要底層實(shí)現(xiàn)TCP IP協(xié)議,都可以用socket進(jìn)行通信。
應(yīng)用層: HTTP FTP SMTP Web
傳輸層: 在兩個(gè)應(yīng)用程序之間提供了邏輯而不是物理的通信基于流的TCP和基于數(shù)據(jù)包的UDP
文件描述符一般是指一個(gè)文件或某個(gè)類似文件的實(shí)體。內(nèi)核(kernel)利用文件描述符(file descriptor)來(lái)訪問文件。文件描述符是非負(fù)整數(shù)。打開現(xiàn)存文件或新建文件時(shí),內(nèi)核會(huì)返回一個(gè)文件描述符。讀寫文件也需要使用文件描述符來(lái)指定待讀寫的文件。
文件描述符在形式上是一個(gè)非負(fù)整數(shù)。實(shí)際上,它是一個(gè)索引值,指向內(nèi)核為每一個(gè)進(jìn)程所維護(hù)的該進(jìn)程打開文件的記錄表。當(dāng)程序打開一個(gè)現(xiàn)有文件或者創(chuàng)建一個(gè)新文件時(shí),內(nèi)核向進(jìn)程返回一個(gè)文件描述符。在程序設(shè)計(jì)中,一些涉及底層的程序編寫往往會(huì)圍繞著文件描述符展開。但是文件描述符這一概念往往只適用于UNIX、
Linux這樣的操作系統(tǒng)。
三、SOCKET連接過程
根據(jù)連接啟動(dòng)的方式以及本地套接字要連接的目標(biāo),套接字之間的連接過程可以分為三個(gè)步驟:服務(wù)器監(jiān)聽,客戶端請(qǐng)求,連接確認(rèn)。
服務(wù)器監(jiān)聽:是服務(wù)器端套接字并不定位具體的客戶端套接字,而是處于等待連接的狀態(tài),實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài)。
客戶端請(qǐng)求:是指由客戶端的套接字提出連接請(qǐng)求,要連接的目標(biāo)是服務(wù)器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務(wù)器的套接字,指出服務(wù)器端套接字的地址和端口號(hào),然后就向服務(wù)器端套接字提出連接請(qǐng)求。
連接確認(rèn):是指當(dāng)服務(wù)器端套接字監(jiān)聽到或者說(shuō)接收到客戶端套接字的連接請(qǐng)求,它就響應(yīng)客戶端套接字的請(qǐng)求,建立一個(gè)新的線程,把服務(wù)器端套接字的描述發(fā)給客戶端,一旦客戶端確認(rèn)了此描述,連接就建立好了。而服務(wù)器端套接字繼續(xù)處于監(jiān)聽狀態(tài),繼續(xù)接收其他客戶端套接字的連接請(qǐng)求。
四、開發(fā)原理
服務(wù)器:使用ServerSocket監(jiān)聽指定的端口,端口可以隨意指定(由于1024以下的端口通常屬于保留端口,在一些操作系統(tǒng)中不可以隨意使用,所以建議使用大于1024的端口),等待客戶連接請(qǐng)求,客戶連接后,會(huì)話產(chǎn)生;在完成會(huì)話后,關(guān)閉連接。
客戶端:使用Socket對(duì)網(wǎng)絡(luò)上某一個(gè)服務(wù)器的某一個(gè)端口發(fā)出連接請(qǐng)求,一旦連接成功,打開會(huì)話;會(huì)話完成后,關(guān)閉Socket。客戶端不需要指定打開的端口,通常臨時(shí)的、動(dòng)態(tài)的分配一個(gè)1024以上的端口。
Socket接口是TCP/IP網(wǎng)絡(luò)的API,Socket接口定義了許多函數(shù)或例程,程序員可以用它們來(lái)開發(fā)TCP/IP網(wǎng)絡(luò)上的應(yīng)用程序。要學(xué)Internet上的TCP/IP網(wǎng)絡(luò)編程,必須理解Socket接口。Socket接口設(shè)計(jì)者最先是將接口放在Unix操作系統(tǒng)里面的。如果了解Unix系統(tǒng)的輸入和輸出的話,就很容易了解Socket了。網(wǎng)絡(luò)的Socket數(shù)據(jù)傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個(gè)類似于打開文件的函數(shù)調(diào)用Socket(),該函數(shù)返回一個(gè)整型的Socket描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^該Socket實(shí)現(xiàn)的。
五、Loadrunner中socket相關(guān)函數(shù)淺析
Loadrunner對(duì)于腳本函數(shù)有一份幫助文檔。利用好此文檔,其實(shí)對(duì)于
性能測(cè)試所需腳本就已足以。
當(dāng)我們打開Create/Edit Scripts,并打開腳本錄制頁(yè)面時(shí),摁下F1便可打開《HP LoadRunner Online Function Reference》。在這幫助文檔中找到“鍵入關(guān)鍵字進(jìn)行查找”輸入框。利用它查找我們所需的socket函數(shù)了。
幾乎所有關(guān)于socket的函數(shù),都是以lrs開頭的。
基本操作函數(shù):
lrs_startup 初始化 WinSock DLL lrs_create_socket 初始化套接字 lrs_send 在數(shù)據(jù)報(bào)上(UDP)或者向流套接字(TCP)發(fā)送數(shù)據(jù) lrs_receive 接收來(lái)自數(shù)據(jù)報(bào)或流套接字的數(shù)據(jù) lrs_disable_socket 禁用套接字操作 lrs_close_socket 關(guān)閉打開的套接字 lrs_cleanup 終止 WinSock DLL 的使用,回收相關(guān)資源。VuGen 在 Windows 上使用 Windows 套接字協(xié)議支持應(yīng)用程序的錄制和回放;而在UNIX 平臺(tái)上僅支持回放 lrs_accept_connection 接受偵聽套接字連接 lrs_close_socket 關(guān)閉打開的套接字 lrs_create_socket 初始化套接字 lrs_disable_socket 禁用套接字操作 lrs_exclude_socket 重播期間排除套接字 lrs_get_socket_attrib 獲取套接字屬性 lrs_get_socket_handler 獲取指定套接字的套接字處理程序 lrs_length_receive 接收來(lái)自指定長(zhǎng)度的緩沖區(qū)的數(shù)據(jù) lrs_receive 接收來(lái)自套接字的數(shù)據(jù) lrs_receive_ex 接收來(lái)自數(shù)據(jù)報(bào)或流套接字的數(shù)據(jù)(具有特定長(zhǎng)度) lrs_send 將數(shù)據(jù)發(fā)送到數(shù)據(jù)報(bào)上或流套接字中 lrs_set_receive_option 設(shè)置套接字接收選項(xiàng) lrs_set_socket_handler 設(shè)置特定套接字的套接字處理程序 lrs_set_socket_options 設(shè)置套接字選項(xiàng) |
緩沖區(qū)函數(shù):
lrs_free_buffer 釋放分配給緩沖區(qū)的內(nèi)存 lrs_get_buffer_by_name 從數(shù)據(jù)文件中獲取緩沖區(qū)及其大小 lrs_get_last_received_buffer 獲取套接字上接收到的最后的緩沖區(qū)及其大小 lrs_get_last_received_buffer_size 獲取套接字上接收到的最后一個(gè)緩沖區(qū)的大小 lrs_get_received_buffer 獲取最后接收到的緩沖區(qū)或其一部分 lrs_get_static_buffer 獲取靜態(tài)緩沖區(qū)或其一部分 lrs_get_user_buffer 獲取套接字的用戶數(shù)據(jù)的內(nèi)容 lrs_get_user_buffer_size 獲取套接字的用戶數(shù)據(jù)的大小 lrs_set_send_buffer 指定要在套接字上發(fā)送的緩沖區(qū) |
環(huán)境函數(shù):
lrs_cleanup 終止Windows套接字 DLL 的使用
lrs_startup 初始化 Windows 套接字 DLL
關(guān)聯(lián)語(yǔ)句函數(shù):
lrs_save_param 將靜態(tài)或接收到的緩沖區(qū)(或緩沖區(qū)部分)保存到參數(shù)中
lrs_save_param_ex 將用戶、靜態(tài)或接收到的緩沖區(qū)(或緩沖區(qū)部分)保存到參數(shù)中
lrs_save_searched_string 在靜態(tài)或接收到的緩沖區(qū)中搜索出現(xiàn)的字符串,將出現(xiàn)字符串的緩沖區(qū)部分保存到參數(shù)中
轉(zhuǎn)換函數(shù):
lrs_ascii_to_ebcdic 將緩沖區(qū)數(shù)據(jù)從 ASCII 格式轉(zhuǎn)換成 EBCDIC 格式
lrs_decimal_to_hex_string 將十進(jìn)制整數(shù)轉(zhuǎn)換為十六進(jìn)制字符串
lrs_ebcdic_to_ascii 將緩沖區(qū)數(shù)據(jù)從 EBCDIC 格式轉(zhuǎn)換成ASCII 格式
lrs_hex_string_to_int 將十六進(jìn)制字符串轉(zhuǎn)換為整數(shù)
超時(shí)函數(shù):(這一堆函數(shù),是可以對(duì)同一個(gè)socket生效的)
lrs_set_accept_timeout 為接受套接字設(shè)置超時(shí)
lrs_set_connect_timeout 為連接到套接字設(shè)置超時(shí)
lrs_set_recv_timeout 執(zhí)行l(wèi)rs_receive命令后,等待服務(wù)器返回消息的超時(shí)時(shí)間,即服務(wù)器的響應(yīng)時(shí)間。
lrs_set_recv_timeout2 創(chuàng)建連接成功,接收到服務(wù)器返回的消息后,獲取匹配消息的超時(shí)時(shí)間。lrs_receive接收到數(shù)據(jù)后,會(huì)和預(yù)期的數(shù)據(jù)長(zhǎng)度進(jìn)行比較,如果長(zhǎng)度不匹配,它將重新從套接字上讀取數(shù)據(jù),直到超時(shí)為止。
lrs_set_send_timeout 為發(fā)送套接字?jǐn)?shù)據(jù)設(shè)置超時(shí)
六、實(shí)戰(zhàn)講解
在此只做簡(jiǎn)單的知識(shí)普及,便于快速上手編寫socket測(cè)試腳本。簡(jiǎn)述創(chuàng)建連接,收發(fā)協(xié)議,關(guān)閉連接的過程。
初始化
//存放通信返回報(bào)文 char * ActualBuffer=""; //存放返回報(bào)文長(zhǎng)度,切記附初值 int numberOfResponse = -1; //鏈接是否創(chuàng)建成功,判斷值 int rc = 0; //返回報(bào)文是否成功,判斷值 int msgOk=-1; //存放返回報(bào)文 char * position=""; //返回報(bào)文是否成功標(biāo)識(shí) char * passMsg="succee"; |
服務(wù)器監(jiān)聽
//--------------創(chuàng)建連接----------------- rc= lrs_create_socket("socket0", "TCP", "LocalHost=0", "RemoteHost=<RemoteHost>", LrsLastArg); if (rc==0){ //判斷連接是否創(chuàng)建成功 lr_output_message("Socket was successfully created "); } else{ lr_output_message("An error occurred while creating the socket, Error Code: %d", rc); } //--------------創(chuàng)建連接----------------- |
收發(fā)協(xié)議
lrs_send("socket0", "buf0", LrsLastArg); //往“socket0”發(fā)送"buf0" lrs_set_receive_option(EndMarker, BinaryStringTerminator, "</html>"); //設(shè)置接收協(xié)議包選項(xiàng),注"</html>"以實(shí)際定義協(xié)議為準(zhǔn),如果不設(shè)置次項(xiàng)。執(zhí)行到lrs_receive的時(shí)候,log里面打印Waiting for writable socket 10 //secs, 0 usecs,都需要等待10秒鐘。是這樣的,因?yàn)槟阍赿ata.ws中定義了recv buffer的長(zhǎng)度,例如你定義為100,但是socket上的返回buffer長(zhǎng)度不 //是100,這時(shí)候,loadrunner會(huì)嘗試再次去讀取,直到讀到長(zhǎng)度為100的buffer才算成功。 lrs_receive("socket0", "buf1","Flags=MSG_PEEK ", LrsLastArg); //將“socket0”中返回的數(shù)據(jù)存放到“buf1”中 |
參數(shù)配置
可能細(xì)心的同學(xué)已經(jīng)發(fā)現(xiàn)了,buf0與buf1是從哪里來(lái)的。其實(shí)這倆兄弟是在data.ws中被定義的,如下所示:
;WSRData 2 1
send buf0 5120
"<參數(shù)化>"
recv buf1 1024
-1
5120:此數(shù)值為socket協(xié)議傳輸內(nèi)容長(zhǎng)度,切記嚴(yán)格輸入正確長(zhǎng)度值。
"<參數(shù)化>":為buf0所傳輸內(nèi)容。相對(duì)于loadrunner的http協(xié)議參數(shù)用{}來(lái)說(shuō),socket協(xié)議參數(shù)化采用<>作為定義符。
接收參數(shù)判斷
在做了接收之后,我們需要提取“buf1”中的某些關(guān)鍵字符作為通信成功標(biāo)識(shí)。
//獲取套接字上接收到的最后的緩沖區(qū)及其大小 lrs_get_last_received_buffer("socket0",&ActualBuffer,&numberOfResponse); //查詢返回報(bào)文是否成功 position = (char *)strstr(ActualBuffer, passMsg); // strstr has returned the address. Now calculate * the offset from the beginning of str msgOk = (int)(position - ActualBuffer + 1); if(msgOk>0){ lr_end_transaction("核心對(duì)私維護(hù)", LR_PASS); lr_output_message("本次交易:%s",ActualBuffer); } else{ lr_end_transaction("核心對(duì)私維護(hù)", LR_FAIL); lr_error_message("本次交易:%s",ActualBuffer); } 關(guān)閉連接 //--------------斷開socket-------------- lrs_disable_socket("socket0", DISABLE_SEND_RECV); //--------------關(guān)閉socket-------------- lrs_close_socket("socket0"); |
六、總結(jié)
簡(jiǎn)要描述了利用Loadrunner編寫socket性能測(cè)試腳本的過程,如有錯(cuò)漏,請(qǐng)予以指正。
摘要: 安裝完TestLink的下一步就是配置了,Testlink的配置信息包含很多方面,從日志信息、與其它bug管理工具的連接、自定義產(chǎn)生的文檔、Email信息配置、用戶認(rèn)證配置、GUI定制、測(cè)試執(zhí)行設(shè)置、測(cè)試規(guī)約、附件、需求支持、混合功能配置等等,在此一并列出。希望對(duì)你的TestLink的配置有所幫助,在此也聲明一點(diǎn),TestLink系統(tǒng)配置是很龐大的,部分信息是從網(wǎng)上搜集的。 1、配置文件概覽 ...
閱讀全文